﻿Imports System
Imports Strings = Microsoft.VisualBasic ' so can use things like left( and right( for strings
Imports ZedGraph
Imports System.IO
Imports System.Reflection
Imports System.Xml
Imports System.Text.RegularExpressions
Imports System.Runtime.InteropServices

Public Class FrmControlPanel
    Inherits System.Windows.Forms.Form

    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function SetThreadExecutionState(ByVal flags As EXECUTION_STATE) As EXECUTION_STATE
    End Function

    <Flags()> _
    Public Enum EXECUTION_STATE As UInteger
        ES_SYSTEM_REQUIRED = &H1
        ES_DISPLAY_REQUIRED = &H2
        ES_CONTINUOUS = &H80000000UI
    End Enum

    Private Sub PreventSleepMode()
        SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS Or EXECUTION_STATE.ES_DISPLAY_REQUIRED Or EXECUTION_STATE.ES_SYSTEM_REQUIRED)
    End Sub

    Private Sub AllowSleepMode()
        SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS)
    End Sub

    Public Delegate Sub ByteSubPointer(ByVal ByteArray() As Byte, ByVal ByteLength As Integer)
    Dim DlgBoxProgStart As New dlgProgStart()
    Dim DlgBoxVset As New dlgVset()
    Dim DlgTempSensors As New dlgTempSensors()

#Region "DragAndDrop"

    Public SelControl As System.Object, Drag1, Drag2, Drag3, Drag4, isMoving As Boolean

    Private Sub H_Top_Left_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles H_Top_Left.MouseDown
        Drag1 = True
        SetVisible(False)
    End Sub

    Private Sub H_Top_Left_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles H_Top_Left.MouseMove
        If Not Drag1 Then Exit Sub
        Me.H_Top_Left.Left += e.X
        Me.H_Top_Left.Top += e.Y
        SelControl.Top = H_Top_Left.Top + 4
        SelControl.Left = H_Top_Left.Left + 4
        SetActive(SelControl)
    End Sub

    Private Sub H_Top_Left_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles H_Top_Left.MouseUp
        Drag1 = False
        SetVisible(True)
        SavePosition()
    End Sub

    Sub SetVisible(ByVal Visibility As Boolean)
        Me.H_Top_Left.Visible = Visibility
    End Sub

    Private Sub SetActive(ByVal button As System.Object)
        SelControl = button
        Me.H_Top_Left.Left = button.Left - 4 : Me.H_Top_Left.Top = button.Top - 4
    End Sub

    Private Sub SavePosition()
        'records positions of items on layout screen
        'default positions
        'cbV1="6,17"
        'cbV2="6,40"
        'cbV3="6,63"

        Settings.cbV1_posn = cbV1.Location
        Settings.cbV2_posn = cbV2.Location
        Settings.cbV3_posn = cbV3.Location
        Settings.cbV4_posn = cbV4.Location
        Settings.cbV5_posn = cbV5.Location
        Settings.cbV6_posn = cbV6.Location
        Settings.cbV7_posn = cbV7.Location
        Settings.cbV8_posn = cbV8.Location
        Settings.cbV9_posn = cbV9.Location
        Settings.cbV10_posn = cbV10.Location
        Settings.cbV11_posn = cbV11.Location
        Settings.cbV12_posn = cbV12.Location
        Settings.cbV13_posn = cbV13.Location
        Settings.cbV14_posn = cbV14.Location
        Settings.cbV15_posn = cbV15.Location
        Settings.cbV16_posn = cbV16.Location

        Settings.T0_posn = lblT0.Location
        Settings.T1_posn = lblT1.Location
        Settings.T2_posn = lblT2.Location
        Settings.T3_posn = lblT3.Location
        Settings.T4_posn = lblT4.Location
        Settings.T5_posn = lblT5.Location
        Settings.T6_posn = lblT6.Location
        Settings.T7_posn = lblT7.Location
        Settings.T8_posn = lblT8.Location
    End Sub

#End Region

#Region "Define transmit comm variables"
    Dim blnGetProg(29) As Boolean
    Dim blnGetABrecipe As Boolean = True
    Dim blnShowBoil As Boolean = False  'used to show boil information as flash message after user request

#End Region

#Region "Misc definitions"

    Dim blnIsConnected As Boolean = False
    Dim blnUpdateCommsTAB As Boolean = My.Settings.asShowCommsTAB
    Dim blnFTPsupportFilesDone As Boolean = False
    Dim serialOKtime As Date    'time stamp when last good serial data received
    Dim blnShowVsetDialog As Boolean = False 'used to trigger dialog box if vset requested and waiting on BT data

    'graph data arrays
    Dim listMashTemp = New PointPairList() 'Mash temperature
    Dim listHLTTemp = New PointPairList() 'HLT temperature
    Dim listMashSP = New PointPairList() 'Mash setpoint
    Dim listHLTsp = New PointPairList() 'HLT setpoint
    Dim listKetTemp As New PointPairList    'Kettle temperature
    Dim listH2Oin As New PointPairList
    Dim listH2Oout As New PointPairList
    Dim listBeer As New PointPairList
    Dim listAux1 As New PointPairList
    Dim listAux2 As New PointPairList
    Dim listAux3 As New PointPairList
    Dim listHLTvol As New PointPairList 'HLT volume
    Dim listHLTvolRaw As New PointPairList
    Dim listKETvol As New PointPairList
    Dim listKETvolRaw As New PointPairList
    Dim listMashVol As New PointPairList
    Dim listMashVolRaw As New PointPairList
    Dim listHltPwr As New PointPairList
    Dim listMtPwr As New PointPairList
    Dim listKetPwr As New PointPairList
    Dim listSteam As New PointPairList

    Dim tempUnitC As Boolean = False
    Dim strTitleDate As String = ""

    Dim blnAllowSerial As Boolean = False

    Dim strDataFileName As String
    Dim intCycleCount As Integer = 0

    Public Const TP_PANEL As Integer = 0
    Public Const TP_LAYOUT As Integer = 1
    Public Const TP_GRAPH As Integer = 2
    Public Const TP_WEB As Integer = 3
    Public Const TP_SESSION As Integer = 4
    Public Const TP_MESSAGES As Integer = 5
    Public Const TP_RX_DATA As Integer = 6
    Public Const TP_TX_DATA As Integer = 7
    Public Const TP_SETTINGS As Integer = 8

    Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Integer) ' for sleep statements
    Public Const DSLENGTH As Integer = 24                   'length of data string from BrewTroller (BrewTroller)
    Dim PacketLength As Integer = DSLENGTH + 3              'the header to synchronise data is four bytes long, and we start at 0

    Dim currReviewRecord As Integer
    Dim strDegreeNotation As String
    Dim ImageNum As Integer = 0   'keeps a record of which image is shown on layout

    Dim intCurrBTstep As Integer = 0
    Dim int32CurrBitMask As Int32 = 0
    Dim blnLoadProfile As Boolean = False
    Private comm As New CommManager()
    Private transType As String = String.Empty

#End Region

#Region "Form events"

    Private Sub FrmControlPanel_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'load saved settings
        LoadMySettings()

        PreventSleepMode()  'ensures computer does not automatically sleep while BTremote is running

        ToolTip1.SetToolTip(lblHLTset, "Hot Liquor Tun setpoint temperature - adjust up and down with buttons above")
        ToolTip1.SetToolTip(lblHLTtemp, "Hot Liquor Tun temperature")
        ToolTip1.SetToolTip(lblKetSet, "Kettle power level - adjust up and down with buttons above")
        ToolTip1.SetToolTip(lblKetTemp, "Kettle temperature")
        ToolTip1.SetToolTip(lblTimer, "Mash inlet manifold temperature")
        ToolTip1.SetToolTip(lblMashSet, "Mash setpoint temperature - adjust up and down with buttons above")
        ToolTip1.SetToolTip(lblMashTemp, "Mash Tun temperature")

        Dim intLogInterval As Integer
        intLogInterval = 20000
        tmrFTPandLog.Interval = intLogInterval              'every x seconds (under settings tab)
        'pbBT2rem.BackColor = Color.Gray                'start with the comms boxes gray
        'pbFTPcomms.BackColor = Color.Gray                   'gray-no comms; red-comms problems; orange-comms not sync; green-ok
        'pbRem2BT.BackColor = Color.Gray
        Dim ModifyFlag As Boolean
        ModifyFlag = False                                  'if modify a value manually then skip FTP download and BrewTroller receive comms

        For i = DI_TS_HLT To DI_TS_AUX3
            'intitialize temp sensor addresses as not assigned - information is retrieved from BT on connect
            DisplayInfo(i) = "[none]"
        Next
    End Sub

    Private Sub FrmControlPanel_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

        AllowSleepMode()

        If cbSerialConnect.Checked = True Then
            'we need to close the comm port before finishing
            CloseComPort()
            cbSerialConnect.Text = "Connect"
            ToolTip1.SetToolTip(cbSerialConnect, "Press to connect to BrewTroller")
        End If

        SaveMySettings()

        End
    End Sub

    Private Sub AppClosing(ByVal sender As Object, ByVal e As ComponentModel.CancelEventArgs) Handles MyBase.Closing

        comm.ClosePort() ' Close COM port when the form is terminated with [X]

    End Sub

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click
        If cbSerialConnect.Checked = True Then
            comm.ClosePort()
            If cbSerialConnect.Checked Then
                cbSerialConnect.Checked = False
            End If
        End If
        SaveMySettings()
        End
    End Sub

    Private Sub cbSerialConnect_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbSerialConnect.CheckedChanged

        If Not String.IsNullOrEmpty(cboPort.Text) Then
            Select Case blnIsConnected
                Case True
                    CloseComPort()
                    cbSerialConnect.Text = "Connect"
                    ConnectToolStripMenuItem.Text = "Connect"
                    ToolTip1.SetToolTip(cbSerialConnect, "Press to connect to BrewTroller")
                    blnAllowSerial = False
                Case False
                    OpenComPort()
                    cbSerialConnect.Text = "Disconnect"
                    ConnectToolStripMenuItem.Text = "Disconnect"
                    ToolTip1.SetToolTip(cbSerialConnect, "Press to disconnect BrewTroller")
                    'blnAllowSerial = True
            End Select
            blnIsConnected = Not blnIsConnected
        Else
            blnIsConnected = False
            MsgBox("Please select a com port from the drop down list on the status bar.", MsgBoxStyle.Information)
        End If

    End Sub

    Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        wbLiveData.Refresh()
    End Sub

#End Region

#Region "Form Timers"

    Private Sub tmrFTPandLog_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrFTPandLog.Tick

        If cbFTPupload.Checked = True Then
            'Call createXML()  'creates the XML file for gauges
            tsslFTPmsg.Text = "FTP up"
            tsslFTPmsg.ToolTipText = "Uploading to web ..."
            System.Windows.Forms.Application.DoEvents()
            blnDoFTPupload = True
        End If
    End Sub

#End Region

#Region "FTP management"

    Sub FTPDownload(ByVal Filename As String)
        ' downloads remotefile to localfile
        Dim localFile As String 'place to store data
        Dim remoteFile As String ' filename is case sensitive this is really important
        Dim host As String = My.Settings.asFTPhost
        Dim username As String = My.Settings.asFTPusername
        Dim password As String = My.Settings.asFTPpassword
        Dim URI As String
        localFile = Application.StartupPath() + "\" + Filename ' so can add Application.StartupPath()  if need to define actual location
        remoteFile = "/" + Filename ' added to remote ftp location
        URI = host + remoteFile ' make up full address
        Try
            Dim ftp As System.Net.FtpWebRequest = CType(System.Net.FtpWebRequest.Create(URI), System.Net.FtpWebRequest)
            ftp.Credentials = New System.Net.NetworkCredential(username, password) ' log in
            ftp.KeepAlive = False ' will be disconnecting after finished
            ftp.UseBinary = True ' binary mode
            ftp.Timeout = 9000 ' timeout after 9 seconds
            ftp.Method = System.Net.WebRequestMethods.Ftp.DownloadFile ' download a file
            ' read in pieces as don't know how big the file is
            Using response As System.Net.FtpWebResponse = CType(ftp.GetResponse, System.Net.FtpWebResponse)
                Using responseStream As IO.Stream = response.GetResponseStream
                    Using fs As New IO.FileStream(localFile, IO.FileMode.Create)
                        Dim buffer(2047) As Byte
                        Dim read As Integer = 0
                        Do
                            read = responseStream.Read(buffer, 0, buffer.Length) ' piece from ftp
                            fs.Write(buffer, 0, read) ' and write to file
                        Loop Until read = 0 ' until no more pieces
                        responseStream.Close() ' close the ftp file
                        fs.Flush() ' flush clear
                        fs.Close() ' and close the file
                    End Using
                    responseStream.Close() ' close it even if nothing was there
                End Using
                response.Close()
                'pbFTPcomms.BackColor = Color.GreenYellow ' green box as it worked
                'ToolTip1.SetToolTip(pbFTPcomms, "FTP download ok")
                tsslFTPmsg.Text = "FTP ok"
                tsslFTPmsg.ToolTipText = "FTP connected"
            End Using
        Catch ' put error codes here
            'pbFTPcomms.BackColor = Color.Red ' red box as it didn't work
            'ToolTip1.SetToolTip(pbFTPcomms, "FTP download failed")
            tsslFTPmsg.ToolTipText = "FTP download failed"
            tsslFTPmsg.Text = "FTP alm"
        End Try
    End Sub

    Sub XMLupload()
        Dim localFile As String 'place to store data
        Dim remoteFile As String ' filename is case sensitive this is really important
        Dim host As String = My.Settings.asFTPhost
        Dim username As String = My.Settings.asFTPusername + "@brewtroller.com"
        Dim password As String = My.Settings.asFTPpassword
        Dim URI As String
        localFile = Application.StartupPath() + "\remoteBTdata.xml"
        remoteFile = "/BTdata.xml"
        URI = host + remoteFile
        URI = "ftp://ftp.brewtroller.com" + remoteFile
        Try
            'Raw FTP data file
            Dim ftp As System.Net.FtpWebRequest = CType(System.Net.FtpWebRequest.Create(URI), System.Net.FtpWebRequest)
            ftp.Credentials = New System.Net.NetworkCredential(username, password) ' log in
            ftp.KeepAlive = True ' will be disconnecting once done
            ftp.UseBinary = True ' use binary comms
            ftp.Timeout = 15000 ' timeout after 9 seconds - very useful as ftp sometimes dies
            ftp.Method = System.Net.WebRequestMethods.Ftp.UploadFile ' start sending file
            Dim fs As New FileStream(localFile, FileMode.Open) ' open local file
            Dim filecontents(fs.Length) As Byte ' read into memory
            fs.Read(filecontents, 0, fs.Length)
            fs.Close() ' close the file
            Dim requestStream As Stream = ftp.GetRequestStream() ' start ftp link
            requestStream.Write(filecontents, 0, filecontents.Length) ' send it
            requestStream.Close() ' close the link

            tsslFTPmsg.ToolTipText = "FTP uploaded" ' text saying it connected
            tsslFTPmsg.Text = "FTP ok"
        Catch 'can't connect
            tsslFTPmsg.ToolTipText = "FTP failed on upload" ' text saying connection failed
            tsslFTPmsg.Text = "FTP alm"
        End Try

    End Sub

    Sub FTPUpload(ByVal Filename As String)
        'used to upload BTpanel.htm, BTpanel.jpg, gauge.swf if they do not exist on remote site
        Dim localFile As String 'place to store data
        Dim remoteFile As String ' filename is case sensitive this is really important
        Dim host As String = My.Settings.asFTPhost
        Dim username As String = My.Settings.asFTPusername + "@brewtroller.com"
        Dim password As String = My.Settings.asFTPpassword
        Dim URI As String
        localFile = Application.StartupPath() + "\" + Filename
        remoteFile = "/" + Filename ' file on ftp server needs "/" added in front
        URI = host + remoteFile
        URI = "ftp://ftp.brewtroller.com" + remoteFile
        Try
            'Raw FTP data file
            Dim ftp As System.Net.FtpWebRequest = CType(System.Net.FtpWebRequest.Create(URI), System.Net.FtpWebRequest)
            ftp.Credentials = New System.Net.NetworkCredential(username, password) ' log in
            ftp.KeepAlive = True ' will be disconnecting once done
            ftp.UseBinary = True ' use binary comms
            ftp.Timeout = 15000 ' timeout after 9 seconds - very useful as ftp sometimes dies
            'Application.DoEvents()
            'timeout (and the clock frequency of 20 secs) may need to be slower for dialup connections
            ftp.Method = System.Net.WebRequestMethods.Ftp.UploadFile ' start sending file
            Dim fs As New FileStream(localFile, FileMode.Open) ' open local file
            Dim filecontents(fs.Length) As Byte ' read into memory
            'Application.DoEvents()
            fs.Read(filecontents, 0, fs.Length)
            fs.Close() ' close the file
            Dim requestStream As Stream = ftp.GetRequestStream() ' start ftp link
            'Application.DoEvents()
            requestStream.Write(filecontents, 0, filecontents.Length) ' send it
            requestStream.Close() ' close the link

            'pbFTPcomms.BackColor = Color.GreenYellow ' change the box to green to say worked ok
            'ToolTip1.SetToolTip(pbFTPcomms, "Connected to remote site")
            tsslFTPmsg.ToolTipText = "FTP uploaded" ' text saying it connected
            tsslFTPmsg.Text = "FTP ok"
        Catch 'can't connect
            'pbFTPcomms.BackColor = Color.Red ' box to red as no connection
            'ToolTip1.SetToolTip(pbFTPcomms, "Live data failed to upload")
            tsslFTPmsg.ToolTipText = "FTP failed on upload" ' text saying connection failed
            tsslFTPmsg.Text = "FTP alm"
        End Try

    End Sub

    Sub ReadFTPFilename() ' so the name of the remote ftp file is the same next time this program is run
        Dim LineOfText As String
        Try
            FileOpen(1, "FTPFilename.txt", OpenMode.Input) ' open the file
            LineOfText = LineInput(1)
            My.Settings.asFTPfilename = LineOfText ' read the name
            FileClose(1)
        Catch ex As Exception
            FileClose(1)
        End Try
    End Sub

#End Region

#Region "System Settings"

    Public Sub SaveMySettings()

        My.Settings.Save()
        setInputLabels()

        Dim intLogInterval As Integer
        intLogInterval = CInt(My.Settings.as_nudLogInterval) * 1000
        tmrFTPandLog.Interval = intLogInterval             'every x seconds (under settings tab)

        'show message on status bar
        tsslMiscInfo.Text = "Program settings saved"
        tsslMiscInfo.Visible = True
        tmrMessages.Interval = 10000  '10 seconds
        tmrMessages.Enabled = True    'show message for one timer tick

    End Sub

    Public Sub LoadMySettings()

        ValveBtns("unlock")

        'retrieve layout settings
        cbV1.Location = Settings.cbV1_posn
        cbV2.Location = Settings.cbV2_posn
        cbV3.Location = Settings.cbV3_posn
        cbV4.Location = Settings.cbV4_posn
        cbV5.Location = Settings.cbV5_posn
        cbV6.Location = Settings.cbV6_posn
        cbV7.Location = Settings.cbV7_posn
        cbV8.Location = Settings.cbV8_posn
        cbV9.Location = Settings.cbV9_posn
        cbV10.Location = Settings.cbV10_posn
        cbV11.Location = Settings.cbV11_posn
        cbV12.Location = Settings.cbV12_posn
        cbV13.Location = Settings.cbV13_posn
        cbV14.Location = Settings.cbV14_posn
        cbV15.Location = Settings.cbV15_posn
        cbV16.Location = Settings.cbV16_posn

        lblT0.Location = Settings.T0_posn
        lblT1.Location = Settings.T1_posn
        lblT2.Location = Settings.T2_posn
        lblT3.Location = Settings.T3_posn
        lblT4.Location = Settings.T4_posn
        lblT5.Location = Settings.T5_posn
        lblT6.Location = Settings.T6_posn
        lblT7.Location = Settings.T7_posn
        lblT8.Location = Settings.T8_posn

        'reset valve settings 
        Settings.v1 = False
        Settings.v2 = False
        Settings.v3 = False
        Settings.v4 = False
        Settings.v5 = False
        Settings.v6 = False
        Settings.v7 = False
        Settings.v8 = False
        Settings.v9 = False
        Settings.v10 = False
        Settings.v11 = False
        Settings.v12 = False
        Settings.v13 = False
        Settings.v14 = False
        Settings.v15 = False
        Settings.v16 = False

        'set paths to application path if not user set
        If My.Settings.asLogPathSet = False Then
            My.Settings.asLogFilePath = Application.StartupPath().ToString
        End If
        If My.Settings.asXMLPathSet = False Then
            My.Settings.asXMLpath = Application.StartupPath().ToString
        End If

        'set main form label based on BT version
        If Settings.asBTversion = "BT1" Then
            Me.rbBT1.Checked = True
        ElseIf Settings.asBTversion = "BT2" Then
            Me.rbBT2.Checked = True
        ElseIf Settings.asBTversion = "FT" Then
            Me.rbFT.Checked = True
        Else
            Me.rbBT1.Checked = True
        End If

        'set Serial Command stack to nothing
        For i = 0 To 100
            strSerialMsg(i) = Nothing
        Next

        'set display panels to working path
        'Keith's code
        Dim rootPath As String = System.Reflection.Assembly.GetExecutingAssembly().Location.ToString()
        If rootPath.Substring(rootPath.LastIndexOf("\"c)).Contains(".exe") Then
            rootPath = rootPath.Substring(0, rootPath.LastIndexOf("\"c) + 1)
        End If

        'Arnie's code
        'Dim appPath As String = Application.StartupPath()
        'Dim rootPath = appPath.Substring(0, appPath.LastIndexOf("bin"))

        wbPanel.Url = New Uri(rootPath + "BTPanel.htm")
        wbPanel.Refresh()
        wbLiveData.Url = New Uri(rootPath + "BTPanel.htm")
        wbLiveData.Refresh()

        cbV1.Text = My.Settings.asV1
        cbV2.Text = My.Settings.asV2
        cbV3.Text = My.Settings.asV3
        cbV4.Text = My.Settings.asV4
        cbV5.Text = My.Settings.asV5
        cbV6.Text = My.Settings.asV6
        cbV7.Text = My.Settings.asV7
        cbV8.Text = My.Settings.asV8
        cbV9.Text = My.Settings.asV9
        cbV10.Text = My.Settings.asV10
        cbV11.Text = My.Settings.asV11
        cbV12.Text = My.Settings.asV12
        cbV13.Text = My.Settings.asV13
        cbV14.Text = My.Settings.asV14
        cbV15.Text = My.Settings.asV15
        cbV16.Text = My.Settings.asV16
        cbV17.Text = My.Settings.asV17
        cbV18.Text = My.Settings.asV18
        cbV19.Text = My.Settings.asV19
        cbV20.Text = My.Settings.asV20
        cbV21.Text = My.Settings.asV21
        cbV22.Text = My.Settings.asV22
        cbV23.Text = My.Settings.asv23
        cbV24.Text = My.Settings.asV24
        cbV25.Text = My.Settings.asV25
        cbV26.Text = My.Settings.asV26
        cbV27.Text = My.Settings.asV27
        cbV28.Text = My.Settings.asV28
        cbV29.Text = My.Settings.asV29
        cbV30.Text = My.Settings.asV30
        cbV31.Text = My.Settings.asV31
        cbV32.Text = My.Settings.asV32

        For i = 0 To 29
            blnGetProg(i) = True
        Next
        comm.SetPortNameValues(cboPort)
        If My.Settings.asComPort <> cboPort.Text Then
            cboPort.SelectedIndex = 0
        End If

        tcMain.SuspendLayout()
        tcMain.TabPages.Clear()
        tcMain.TabPages.Add(tpPanel)
        If My.Settings.asShowControlTAB Then tcMain.TabPages.Add(tpControl)
        'tcMain.TabPages.Add(tpLayout)
        tcMain.TabPages.Add(tpRecipe)
        If My.Settings.asShowGraphTAB Then tcMain.TabPages.Add(tpGraph)
        If My.Settings.asShowCommsTAB Then tcMain.TabPages.Add(tpComms)
        tcMain.TabPages.Add(tpSetttings)
        tcMain.ResumeLayout()

        DisplayInfo(DI_HLT_TEMP) = "--.-"
        DisplayInfo(DI_MASH_TEMP) = "--.-"
        DisplayInfo(DI_KET_TEMP) = "--.-"

        DisplayInfo(DI_HLT_SET) = "--.-"
        DisplayInfo(DI_MASH_SET) = "--.-"
        DisplayInfo(DI_KET_SET) = "--.-"

        DisplayInfo(DI_HLT_VOL) = "--.-"
        DisplayInfo(DI_MASH_VOL) = "--.-"
        DisplayInfo(DI_KET_VOL) = "--.-"

        DisplayInfo(DI_HLT_HEAT) = "--"
        DisplayInfo(DI_MASH_HEAT) = "--"
        DisplayInfo(DI_KET_HEAT) = "--"

        DisplayInfo(DI_STEP_DESCR) = "[none]"

        DisplayInfo(DI_TIME_VAL) = "00:00"

        'set input names from settings
        setInputLabels()

        'enable scroll bar on form if required
        If Settings.asShowScrollbar Then Me.AutoScroll = True

        'Force upload of support files for flash on initial FTP connection
        My.Settings.asBlnFTPsupportFilesOK = False  'NOTE: a better method would be to check if file exists

    End Sub

#End Region

#Region "Graphing and Logging"

    Private Sub CreateNewGraph()

        GetGraphDataFromFile()
        CreateFilteredGraph()
        UpdateGraph()

    End Sub


    Private Sub GetGraphDataFromFile()

        Dim strDataFile As String = My.Settings.asStrGraphDataFile
        Dim strFileExt As String = IO.Path.GetExtension(strDataFile)
        Dim dataVerOffset As Integer = 0  'btl files do not include a date/time field but btd need offset to read data correctly

        If strDataFile.Length = 0 Or strFileExt.Length = 0 Then
            'we have a problem with the filename so we need to start afresh.
            loadGraphFile()
            Exit Sub
        End If
        If strFileExt <> "btl" Then dataVerOffset = 1

        'GET DATA FROM FILE
        '------------------

        Try
            Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(strDataFile)

                Dim RecNum
                Dim currentRow As String()
                Dim itemID As Integer = 0
                Dim timeElapsed As Double
                Dim dtTime As Date
                Dim strClass As String
                Dim strMsg As String
                Dim tempID As Integer
                Dim tempVal As Double
                Dim tempUnitVal As String
                Dim startTimeOK As Boolean = False
                Dim startTimeVal As Double
                Dim recTime As Double
                Dim lastTimeElapsed As Double
                Dim recFilter As Integer = 0
                Dim lastMashingTime As Double
                Dim rowCounter As Integer = 0
                Dim blnAddThisRecord As Boolean = False

                'clear previously loaded data (if any)
                listAux1.Clear()
                listAux2.Clear()
                listAux3.Clear()
                listBeer.Clear()
                listH2Oin.Clear()
                listH2Oout.Clear()
                listHltPwr.Clear()
                listHLTsp.Clear()
                listHLTTemp.Clear()
                listHLTvol.Clear()
                listHLTvolRaw.Clear()
                listKetPwr.Clear()
                listKetTemp.Clear()
                listKETvol.Clear()
                listKETvolRaw.Clear()
                listMashSP.Clear()
                listMashTemp.Clear()
                listMashVol.Clear()
                listMashVolRaw.Clear()
                listMtPwr.Clear()
                listSteam.Clear()

                lblGraphStatus.Text = "Loading data"
                tspbarLoad.Visible = True

                'get data from file
                MyReader.TextFieldType = FileIO.FieldType.Delimited
                MyReader.SetDelimiters(vbTab)
                While Not MyReader.EndOfData
                    Try
                        currentRow = MyReader.ReadFields()
                        Dim currentField As String
                        itemID = 0
                        For Each currentField In currentRow
                            Select Case itemID

                                Case SER_TIME
                                    If dataVerOffset = 0 Then
                                        timeElapsed = Val(currentField)
                                    Else
                                        'correct for file write bug in releases prior to ver 0.5
                                        If currentField.Substring(0, 3) = "0  " Then
                                            currentField = currentField.Substring(1, currentField.Length - 1)
                                            currentField = currentField.Trim
                                        End If
                                        dtTime = CDate(currentField)
                                        timeElapsed = dtTime.ToOADate
                                        strTitleDate = dtTime.ToLongDateString
                                        End If

                                Case SER_CLASS + dataVerOffset
                                        strClass = currentField
                                Case SER_MSG + dataVerOffset
                                        strMsg = currentField
                                Case TEMP_ID + dataVerOffset
                                        tempID = Val(currentField)
                                Case TEMP_VAL + dataVerOffset
                                    tempVal = Val(currentField)
                                    If tempVal > 300 And tempVal <> 0 Then tempVal /= 100
                                Case TEMP_UNIT + dataVerOffset
                                        tempUnitVal = Val(currentField)
                            End Select
                            itemID = itemID + 1

                        Next
                    Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
                        MsgBox("Line " & ex.Message & _
                        "is not valid and will be skipped.")
                    End Try

                    rowCounter = rowCounter + 1
                    If rowCounter >= 500 Then
                        rowCounter = 0

                        'progress bar
                        tspbarLoad.Value += 1
                        If tspbarLoad.Value = 100 Then tspbarLoad.Value = 0
                        Application.DoEvents()
                    End If


                    If dataVerOffset = 0 Then
                        recTime = recTime + (1 / 60)    'time in minutes
                        recFilter = recFilter + 1
                        If recFilter = 20 Then recFilter = 0 'only record 1 in 20 data items
                    Else
                        recTime = timeElapsed
                        recFilter = 0   'we show all records
                    End If

                    If timeElapsed = 0 Then blnAddThisRecord = False
                    If recFilter <> 0 Then
                        blnAddThisRecord = False
                    Else
                        blnAddThisRecord = True
                    End If

                    If blnAddThisRecord Then

                        'look for temperature information
                        If strMsg = "TEMP" Then

                            If tempID = 0 Then
                                'we have HLT temp
                                'add data point for graphing
                                listHLTTemp.Add(recTime, tempVal)

                            ElseIf tempID = 1 Then
                                'we have mash temp
                                'add data point for graphing
                                listMashTemp.Add(recTime, tempVal)
                            ElseIf tempID = 2 Then
                                'we have kettle temp
                                'add data point for graphing
                                listKetTemp.Add(recTime, tempVal)
                            ElseIf tempID = 3 Then
                                'we have water in temp
                                'add data point for graphing
                                listH2Oin.Add(recTime, tempVal)
                            ElseIf tempID = 4 Then
                                'we have kettle temp
                                'add data point for graphing
                                listH2Oout.Add(recTime, tempVal)
                            ElseIf tempID = 5 Then
                                'we have beer temp
                                'add data point for graphing
                                listBeer.Add(recTime, tempVal)
                            ElseIf tempID = 6 Then
                                'we have aux1 temp
                                'add data point for graphing
                                listAux1.Add(recTime, tempVal)
                            ElseIf tempID = 7 Then
                                'we have aux2 temp
                                'add data point for graphing
                                listAux2.Add(recTime, tempVal)
                            ElseIf tempID = 8 Then
                                'we have aux2 temp
                                'add data point for graphing
                                listAux3.Add(recTime, tempVal)
                            End If
                        ElseIf strMsg = "SETPOINT" Then
                            If tempID = 0 Then
                                'we have HLT setpoint
                                'add data point for graphing
                                listHLTsp.Add(recTime, tempVal)
                            ElseIf tempID = 1 Then
                                'we have mash setpoint
                                'add data point for graphing
                                listMashSP.Add(recTime, tempVal)
                            End If
                        ElseIf strMsg = "VOL" Then
                            If tempID = 0 Then
                                'we have HLT volume
                                'add data point for graphing
                                listHLTvol.Add(recTime, tempVal)
                            ElseIf tempID = 1 Then
                                'we have mash volume
                                'add data point for graphing
                                listMashVol.Add(recTime, tempVal)
                            ElseIf tempID = 2 Then
                                'we have kettle volume
                                'add data point for graphing
                                listKETvol.Add(recTime, tempVal)
                            End If
                        ElseIf strMsg = "VOL_READ" Then
                            If tempID = 0 Then
                                'we have HLT raw volume
                                'add data point for graphing
                                listHLTvolRaw.Add(recTime, tempVal)
                            ElseIf tempID = 1 Then
                                'we have mash raw volume
                                'add data point for graphing
                                listMashVolRaw.Add(recTime, tempVal)
                            ElseIf tempID = 2 Then
                                'we have kettle raw volume
                                'add data point for graphing
                                listKETvolRaw.Add(recTime, tempVal)
                            End If
                        End If
                    End If
                End While
            End Using

            tspbarLoad.Visible = False
            tspbarLoad.Value = 0

        Catch ex As Exception
            MsgBox("Error occurred retrieving graph data from file." & vbCrLf & ex.Message)
        End Try

    End Sub

    Private Sub CreateFilteredGraph()

        'CREATE GRAPH ELEMENTS
        '---------------------

        'data file contains session date information
        Dim strDataFile As String = My.Settings.asStrGraphDataFile
        Dim strFileExt As String = IO.Path.GetExtension(strDataFile)
        Dim dataVerOffset As Integer = 0  'btl files do not include a date/time field but btd need offset to read data correctly
        If strFileExt <> "btl" Then dataVerOffset = 1

        'define graph, title and axis info
        Dim myPane As GraphPane = zg1.GraphPane
        Dim strGraphTitle As String = "BrewTroller brew session"
        Dim strXaxisTitle As String = "Time"
        Dim blnFoundDate As Boolean = False

        'define graphlines
        Dim MashTemp As New GraphLine
        Dim MashSet As New GraphLine
        Dim hltTemp As New GraphLine
        Dim hltSet As New GraphLine
        Dim ketTemp As New GraphLine
        Dim ketSet As New GraphLine
        Dim H2Oin As New GraphLine
        Dim H2Oout As New GraphLine
        Dim Beer As New GraphLine
        Dim Aux1 As New GraphLine
        Dim Aux2 As New GraphLine
        Dim volHLT As New GraphLine
        Dim volHLTraw As New GraphLine
        Dim volMash As New GraphLine
        Dim volMashRaw As New GraphLine
        Dim volKet As New GraphLine
        Dim volKetRaw As New GraphLine
        Dim hltPwr As New GraphLine
        Dim mtPwr As New GraphLine
        Dim ketPwr As New GraphLine
        Dim Steam As New GraphLine

        'set defaults for graphlines
        MashTemp.Color = Color.Red
        MashTemp.weight = 2
        MashTemp.GraphTitle = "Mash Temp"

        MashSet.Color = Color.Red
        MashSet.weight = 1
        MashSet.GraphTitle = "Mash Set"

        hltTemp.Color = Color.Blue
        hltTemp.weight = 2
        hltTemp.GraphTitle = "HLT Temp"

        hltSet.Color = Color.Blue
        hltSet.weight = 1
        hltSet.GraphTitle = "HLT Set"

        ketTemp.Color = Color.YellowGreen
        ketTemp.weight = 2
        ketTemp.GraphTitle = "Ket Temp"

        ketSet.Color = Color.YellowGreen
        ketSet.weight = 1
        ketSet.GraphTitle = "Ket Set"

        H2Oin.Color = Color.Black
        H2Oin.weight = 2
        H2Oin.GraphTitle = "Water in"

        H2Oout.Color = Color.BlueViolet
        H2Oout.weight = 2
        H2Oout.GraphTitle = "Water out"

        Beer.Color = Color.Brown
        Beer.weight = 2
        Beer.GraphTitle = "Beer"

        Aux1.Color = Color.CadetBlue
        Aux1.weight = 2
        Aux1.GraphTitle = "Aux1"

        Aux2.Color = Color.Chartreuse
        Aux2.weight = 2
        Aux2.GraphTitle = "Aux2"

        volHLT.Color = Color.Peru
        volHLT.weight = 2
        volHLT.GraphTitle = "HLT vol"

        volHLTraw.Color = Color.Magenta
        volHLTraw.weight = 2
        volHLTraw.GraphTitle = "HLT raw vol"

        volKet.Color = Color.PaleVioletRed
        volKet.weight = 2
        volKet.GraphTitle = "Ket vol"

        volKetRaw.Color = Color.MidnightBlue
        volKetRaw.weight = 2
        volKetRaw.GraphTitle = "Ket raw vol"

        volMash.Color = Color.SeaGreen
        volMash.weight = 2
        volMash.GraphTitle = "Mash vol"

        volMashRaw.Color = Color.OrangeRed
        volMashRaw.weight = 2
        volMashRaw.GraphTitle = "Mash raw vol"

        'FILTER GRAPH DATA
        '-----------------

        Dim strGrTemps As String
        Dim strGrMisc As String
        Dim strGrTimeLine As String

        'X scope (time axis)
        Dim Step_All As Boolean = False
        Dim Step_Fill As Boolean = False
        Dim Step_Delay As Boolean = False
        Dim Step_Preheat As Boolean = False
        Dim Step_DoughIn As Boolean = False
        Dim Step_Protein As Boolean = False
        Dim Step_Sacch As Boolean = False
        Dim Step_MO As Boolean = False
        Dim Step_Sparge As Boolean = False
        Dim Step_Boil As Boolean = False
        Dim Step_Chill As Boolean = False
        Dim Step_Custom As Boolean = False

        Dim blnFill As Boolean = False
        Dim blnDelay As Boolean = False
        Dim blnPreHeat As Boolean = False
        Dim blnDoughIn As Boolean = False
        Dim blnProtein As Boolean = False
        Dim blnSacch As Boolean = False
        Dim blnMO As Boolean = False
        Dim blnSparge As Boolean = False
        Dim blnBoil As Boolean = False
        Dim blnChill As Boolean = False
        Dim blnShowVol As Boolean = False

        'Y scope (temperature axis)
        Dim Temp_All As Boolean = False
        Dim Temp_Mash_and_HLT As Boolean = False
        Dim Temp_Boil As Boolean = False

        'Populate selected items into string
        For intNum = 0 To lbGrTemps.SelectedItems.Count - 1
            strGrTemps &= " " & lbGrTemps.SelectedItems(intNum)
        Next intNum
        For intNum = 0 To lbGrMisc.SelectedItems.Count - 1
            strGrMisc &= " " & lbGrMisc.SelectedItems(intNum)
        Next intNum
        For intNum = 0 To lbGrTimeLine.SelectedItems.Count - 1
            strGrTimeLine &= " " & lbGrTimeLine.SelectedItems(intNum)
        Next intNum

        'ensure we have some items selected
        Try
            If strGrTemps = "" And strGrMisc = "" Then
                'no items are selected
                MsgBox("Please select items to show on your graph and use the 'refresh' button.", MsgBoxStyle.Information)
                Exit Sub
            End If
        Catch ex As Exception

        End Try

        'Temperature settings - show selected graphlines
        If InStr(strGrTemps, "HL tun") <> 0 Then hltTemp.show = True
        If InStr(strGrTemps, "Mash tun") <> 0 Then MashTemp.show = True
        If InStr(strGrTemps, "Kettle") <> 0 Then ketTemp.show = True
        If InStr(strGrTemps, "HL target") <> 0 Then hltSet.show = True
        If InStr(strGrTemps, "MT target") <> 0 Then MashSet.show = True
        If InStr(strGrTemps, "H2Oin") <> 0 Then H2Oin.show = True
        If InStr(strGrTemps, "H2Oout") <> 0 Then H2Oout.show = True
        If InStr(strGrTemps, "Beer") <> 0 Then Beer.show = True
        If InStr(strGrTemps, "Aux1") <> 0 Then Aux1.show = True
        If InStr(strGrTemps, "Aux2") <> 0 Then Aux2.show = True

        'Misc input settings - show selected graphlines
        If InStr(strGrMisc, "HLT power") <> 0 Then hltPwr.show = True
        If InStr(strGrMisc, "MT power") <> 0 Then mtPwr.show = True
        If InStr(strGrMisc, "Kettle power") <> 0 Then ketPwr.show = True
        If InStr(strGrMisc, "HL tun vol") <> 0 Then volHLT.show = True
        If InStr(strGrMisc, "Mash vol") <> 0 Then volMash.show = True
        If InStr(strGrMisc, "Kettle vol") <> 0 Then volKet.show = True
        If InStr(strGrMisc, "Steam") <> 0 Then Steam.show = True
        If InStr(strGrMisc, "HLT vol raw") <> 0 Then volHLTraw.show = True
        If InStr(strGrMisc, "MT vol raw") <> 0 Then volMashRaw.show = True
        If InStr(strGrMisc, "KET vol raw") <> 0 Then volKetRaw.show = True

        'Timeline (X scope) settings - filter by steps or custom time settings
        If InStr(strGrTimeLine, "ALL") <> 0 Then Step_All = True
        If InStr(strGrTimeLine, "Fill") <> 0 Then Step_Fill = True
        If InStr(strGrTimeLine, "Delay") <> 0 Then Step_Delay = True
        If InStr(strGrTimeLine, "Pre-heat") <> 0 Then Step_Preheat = True
        If InStr(strGrTimeLine, "Dough-in") <> 0 Then Step_DoughIn = True
        If InStr(strGrTimeLine, "Protein Rest") <> 0 Then Step_Protein = True
        If InStr(strGrTimeLine, "Sacch Rest") <> 0 Then Step_Sacch = True
        If InStr(strGrTimeLine, "Mash Out") <> 0 Then Step_MO = True
        If InStr(strGrTimeLine, "Sparge") <> 0 Then Step_Sparge = True
        If InStr(strGrTimeLine, "Boil") <> 0 Then Step_Boil = True
        If InStr(strGrTimeLine, "Chill") <> 0 Then Step_Chill = True
        If InStr(strGrTimeLine, "CUSTOM") <> 0 Then Step_Custom = True
        'ensure there is at least one timebase option selected
        If strGrTimeLine = "" Then Step_All = True

        'clear previously loaded data (if any)
        zg1.GraphPane.CurveList.Clear()

        'update status info to graph window
        lblGraphStatus.Text = "Processing data, please wait ..."
        Application.DoEvents()

        'SET GRAPH AXES AND TITLES
        '-------------------------

        'set Y axis labels

        Dim blnTempY1 As Boolean = False
        Dim blnTempY2 As Boolean = False
        Dim blnVolY1 As Boolean = False
        Dim blnVolY2 As Boolean = False
        Dim blnPwrY1 As Boolean = False
        Dim blnPwrY2 As Boolean = False
        Dim blnShowTemps As Boolean = True
        Dim blnShowPwr As Boolean = False
        blnShowVol = False

        If strGrTemps = "" Then
            blnShowTemps = False
        End If

        If hltPwr.show Then blnShowPwr = True
        If ketPwr.show Then blnShowPwr = True
        If mtPwr.show Then blnShowPwr = True

        If volHLT.show Then blnShowVol = True
        If volHLTraw.show Then blnShowVol = True
        If volMash.show Then blnShowVol = True
        If volMashRaw.show Then blnShowVol = True
        If volKet.show Then blnShowVol = True
        If volKetRaw.show Then blnShowVol = True

        If blnShowVol And blnShowTemps Then
            blnVolY1 = True
            blnTempY2 = True
        ElseIf blnShowPwr And blnShowVol Then
            blnVolY1 = True
            blnPwrY2 = True
        ElseIf blnShowTemps And blnShowPwr Then
            blnTempY1 = True
            blnPwrY2 = True
        ElseIf blnShowTemps And blnShowPwr And blnShowVol Then
            blnVolY1 = True
            blnTempY2 = True
            'cannot display three axes
        ElseIf blnShowTemps Then
            blnTempY1 = True
        ElseIf blnShowPwr Then
            blnShowPwr = True
        ElseIf blnShowVol Then
            blnVolY1 = True
        End If

        If blnVolY1 Then myPane.YAxis.Title.Text = "volume"
        If blnVolY2 Then myPane.Y2Axis.Title.Text = "volume"
        If blnTempY1 Then myPane.YAxis.Title.Text = "temperature"
        If blnTempY2 Then myPane.Y2Axis.Title.Text = "temperature"
        If blnPwrY1 Then myPane.YAxis.Title.Text = "power"
        If blnPwrY2 Then myPane.Y2Axis.Title.Text = "power"

        Dim blnUseY2 As Boolean = False
        If blnPwrY2 = True Then blnUseY2 = True
        If blnVolY2 = True Then blnUseY2 = True
        If blnTempY2 = True Then blnUseY2 = True

        If blnUseY2 Then
            myPane.Y2Axis.IsVisible = True
            myPane.Y2Axis.MajorGrid.IsVisible = True
        Else
            myPane.Y2Axis.IsVisible = False
            myPane.Y2Axis.MajorGrid.IsVisible = False
        End If

        'set time axis type
        If dataVerOffset = 1 Then
            myPane.XAxis.Type = AxisType.Date
        Else
            myPane.XAxis.Type = AxisType.Linear
        End If

        ' Set the titles and axis labels
        If dataVerOffset = 1 Then
            strGraphTitle = strGraphTitle + vbCrLf + strTitleDate
        End If
        myPane.Title.Text = strGraphTitle
        myPane.XAxis.Title.Text = strXaxisTitle

        'Show the x axis grid
        myPane.XAxis.MajorGrid.IsVisible = True        'Manually set the axis range
        myPane.XAxis.MajorTic.Size = 2

        'Display the Y axis grid lines
        myPane.YAxis.MajorGrid.IsVisible = True

        'Auto scale the X axis
        myPane.XAxis.Scale.MaxAuto = True
        myPane.XAxis.Scale.MinAuto = True

        'Auto scale the Y axis
        myPane.YAxis.Scale.MaxAuto = True
        myPane.YAxis.Scale.MinAuto = True

        'SET GRAPH CURVES
        '----------------

        If MashSet.show Then
            Dim myCurve As LineItem = myPane.AddCurve(MashSet.GraphTitle, listMashSP, MashSet.Color, SymbolType.None)
            myCurve.Line.Width = MashSet.weight
            If blnTempY2 Then myCurve.IsY2Axis = True
        End If

        If MashTemp.show Then
            Dim myCurve2 As LineItem = myPane.AddCurve(MashTemp.GraphTitle, listMashTemp, MashTemp.Color, SymbolType.None)
            myCurve2.Line.Width = MashTemp.weight
            If blnTempY2 Then myCurve2.IsY2Axis = True
        End If

        If hltTemp.show Then
            Dim myCurve3 As LineItem = myPane.AddCurve(hltTemp.GraphTitle, listHLTTemp, hltTemp.Color, SymbolType.None)
            myCurve3.Line.Width = hltTemp.weight
            If blnTempY2 Then myCurve3.IsY2Axis = True
        End If

        If hltSet.show Then
            Dim myCurve4 As LineItem = myPane.AddCurve(hltSet.GraphTitle, listHLTsp, hltSet.Color, SymbolType.None)
            myCurve4.Line.Width = hltSet.weight
            If blnTempY2 Then myCurve4.IsY2Axis = True
        End If

        If ketTemp.show Then
            Dim myCurve5 As LineItem = myPane.AddCurve(ketTemp.GraphTitle, listKetTemp, ketTemp.Color, SymbolType.None)
            myCurve5.Line.Width = ketTemp.weight
            If blnTempY2 Then myCurve5.IsY2Axis = True
        End If

        If volHLT.show Then
            Dim myCurve6 As LineItem = myPane.AddCurve(volHLT.GraphTitle, listHLTvol, volHLT.Color, SymbolType.None)
            myCurve6.Line.Width = volHLT.weight
            If blnTempY2 Then myCurve6.IsY2Axis = True
        End If

        If volHLTraw.show Then
            Dim myCurve7 As LineItem = myPane.AddCurve(volHLTraw.GraphTitle, listHLTvolRaw, volHLTraw.Color, SymbolType.None)
            myCurve7.Line.Width = volHLTraw.weight
            If blnVolY2 Then myCurve7.IsY2Axis = True
        End If

        If volKet.show Then
            Dim myCurve8 As LineItem = myPane.AddCurve(volKet.GraphTitle, listKETvol, volKet.Color, SymbolType.None)
            myCurve8.Line.Width = volKet.weight
            If blnVolY2 Then myCurve8.IsY2Axis = True
        End If

        If volKetRaw.show Then
            Dim myCurve9 As LineItem = myPane.AddCurve(volKetRaw.GraphTitle, listKETvolRaw, volKetRaw.Color, SymbolType.None)
            myCurve9.Line.Width = volKetRaw.weight
            If blnVolY2 Then myCurve9.IsY2Axis = True
        End If

        If volMash.show Then
            Dim myCurve10 As LineItem = myPane.AddCurve(volMash.GraphTitle, listMashVol, volMash.Color, SymbolType.None)
            myCurve10.Line.Width = volMash.weight
            If blnVolY2 Then myCurve10.IsY2Axis = True
        End If

        If volMashRaw.show Then
            Dim myCurve11 As LineItem = myPane.AddCurve(volMashRaw.GraphTitle, listMashVolRaw, volMashRaw.Color, SymbolType.None)
            myCurve11.Line.Width = volMashRaw.weight
            If blnVolY2 Then myCurve11.IsY2Axis = True
        End If

        If H2Oin.show Then
            Dim myCurve12 As LineItem = myPane.AddCurve(H2Oin.GraphTitle, listH2Oin, H2Oin.Color, SymbolType.None)
            myCurve12.Line.Width = H2Oin.weight
        End If

        If H2Oout.show Then
            Dim myCurve13 As LineItem = myPane.AddCurve(H2Oout.GraphTitle, listH2Oout, H2Oout.Color, SymbolType.None)
            myCurve13.Line.Width = H2Oout.weight
            If blnTempY2 Then myCurve13.IsY2Axis = True
        End If

        If Beer.show Then
            Dim myCurve14 As LineItem = myPane.AddCurve(Beer.GraphTitle, listBeer, Beer.Color, SymbolType.None)
            myCurve14.Line.Width = Beer.weight
            If blnTempY2 Then myCurve14.IsY2Axis = True
        End If

        If hltPwr.show Then
            Dim myCurve15 As LineItem = myPane.AddCurve(hltPwr.GraphTitle, listHltPwr, hltPwr.Color, SymbolType.None)
            myCurve15.Line.Width = hltPwr.weight
            If blnPwrY2 Then myCurve15.IsY2Axis = True
        End If

        If mtPwr.show Then
            Dim myCurve16 As LineItem = myPane.AddCurve(mtPwr.GraphTitle, listMtPwr, mtPwr.Color, SymbolType.None)
            myCurve16.Line.Width = mtPwr.weight
            If blnPwrY2 Then myCurve16.IsY2Axis = True
        End If

        If ketPwr.show Then
            Dim myCurve16 As LineItem = myPane.AddCurve(ketPwr.GraphTitle, listKetPwr, ketPwr.Color, SymbolType.None)
            myCurve16.Line.Width = ketPwr.weight
            If blnPwrY2 Then myCurve16.IsY2Axis = True
        End If

        If Steam.show Then
            Dim myCurve17 As LineItem = myPane.AddCurve(Steam.GraphTitle, listSteam, Steam.Color, SymbolType.None)
            myCurve17.Line.Width = Steam.weight
            If blnPwrY2 Then myCurve17.IsY2Axis = True
        End If

        ' Fill the axis background with a color gradient
        myPane.Chart.Fill = New Fill(Color.White, Color.LightGoldenrodYellow, 45.0F)

        ' Fill the pane background with a color gradient
        myPane.Fill = New Fill(Color.White, Color.FromArgb(220, 220, 255), 45.0F)

        lblGraphStatus.Text = "File: " + strDataFile
    End Sub

    Private Sub UpdateGraph()

        'forces a graph redraw with refreshed data

        'refrash auto axes
        zg1.AxisChange()

        'force a redraw
        zg1.Invalidate()

    End Sub


    Private Sub loadGraphFile()

        Dim bExOccured As Boolean

        Dim strDataFile As String

        'open file dialog
        Dim MyFileOpen As New System.Windows.Forms.OpenFileDialog
        MyFileOpen.InitialDirectory = My.Settings.asLogFilePath
        Dim strFileExt As String    'checks extension for version compatability btd & btl
        Dim retVal As DialogResult

        Try
            ' does not add an extension to a file name if the user omits the extension
            MyFileOpen.AddExtension = True

            'dialog box does not allow multiple files to be selected
            MyFileOpen.Multiselect = False

            MyFileOpen.Filter = "BrewTroller data files (*.btd;*.btl)|*.btd;*.btl"

            retVal = MyFileOpen.ShowDialog()
            If retVal = Windows.Forms.DialogResult.OK Then

                If MyFileOpen.CheckFileExists = True And MyFileOpen.CheckPathExists = True Then

                    My.Settings.asStrGraphDataFile = MyFileOpen.FileName    'save current filename
                    CreateNewGraph()

                End If
            ElseIf retVal = Windows.Forms.DialogResult.Cancel Then
                'action cancelled
                Exit Sub

            End If
        Catch ex1 As AccessViolationException
            MsgBox(ex1.StackTrace.ToString)
            bExOccured = True
        Catch ex As Exception
            MsgBox(ex.StackTrace.ToString)
            bExOccured = True
        Finally
            If bExOccured = True Then
                MsgBox("Program executed with some errors!!!")
            End If
        End Try

        If bExOccured Then
            MsgBox("Problem loading log data file, cannot graph result.")
            lblGraphStatus.Text = "Problem loading data file"
            Exit Sub
        End If


    End Sub

#End Region

#Region "Panel"

    Private Sub UpdateControlPanel()

        'Shows information on the control panel and generates xml for the web panel
        'using data from DisplayInfo(x)

        lblHLTtemp.Text = DisplayInfo(DI_HLT_TEMP)
        lblMashTemp.Text = DisplayInfo(DI_MASH_TEMP)
        lblKetTemp.Text = DisplayInfo(DI_KET_TEMP)

        lblT0.Text = DisplayInfo(DI_HLT_TEMP)
        lblT1.Text = DisplayInfo(DI_MASH_TEMP)
        lblT2.Text = DisplayInfo(DI_KET_TEMP)
        lblT3.Text = DisplayInfo(DI_TEMP_H2O_IN)
        lblT4.Text = DisplayInfo(DI_TEMP_H2O_OUT)
        lblT5.Text = DisplayInfo(DI_TEMP_BEER)
        lblT6.Text = DisplayInfo(DI_TEMP_AUX1)
        lblT7.Text = DisplayInfo(DI_TEMP_AUX2)
        lblT8.Text = DisplayInfo(DI_TEMP_AUX3)

        'map "other inputs" depending on settings
        Select Case My.Settings.as1input
            Case "Water In Temperature"
                tb1input.Text = DisplayInfo(DI_TEMP_H2O_IN)
            Case "Water Out Temperature"
                tb1input.Text = DisplayInfo(DI_TEMP_H2O_OUT)
            Case "Beer Out Temperature"
                tb1input.Text = DisplayInfo(DI_TEMP_BEER)
            Case "Aux 1 Temperature"
                tb1input.Text = DisplayInfo(DI_TEMP_AUX1)
            Case "Aux 2 Temperature"
                tb1input.Text = DisplayInfo(DI_TEMP_AUX2)
            Case "Steam(Pressure)"
                tb1input.Text = DisplayInfo(DI_STEAM_HEAT)
            Case "Raw HLT level"
                tb1input.Text = DisplayInfo(DI_RAW_HLT)
            Case "Raw Mash Tun level"
                tb1input.Text = DisplayInfo(DI_RAW_MASH)
            Case "Raw Kettle level"
                tb1input.Text = DisplayInfo(DI_RAW_KET)
        End Select

        Select Case My.Settings.as2input
            Case "Water In Temperature"
                tb2input.Text = DisplayInfo(DI_TEMP_H2O_IN)
            Case "Water Out Temperature"
                tb2input.Text = DisplayInfo(DI_TEMP_H2O_OUT)
            Case "Beer Out Temperature"
                tb2input.Text = DisplayInfo(DI_TEMP_BEER)
            Case "Aux 1 Temperature"
                tb2input.Text = DisplayInfo(DI_TEMP_AUX1)
            Case "Aux 2 Temperature"
                tb2input.Text = DisplayInfo(DI_TEMP_AUX2)
            Case "Steam(Pressure)"
                tb2input.Text = DisplayInfo(DI_STEAM_HEAT)
            Case "Raw HLT level"
                tb2input.Text = DisplayInfo(DI_RAW_HLT)
            Case "Raw Mash Tun level"
                tb2input.Text = DisplayInfo(DI_RAW_MASH)
            Case "Raw Kettle level"
                tb2input.Text = DisplayInfo(DI_RAW_KET)
        End Select

        Select Case My.Settings.as3input
            Case "Water In Temperature"
                tb3input.Text = DisplayInfo(DI_TEMP_H2O_IN)
            Case "Water Out Temperature"
                tb3input.Text = DisplayInfo(DI_TEMP_H2O_OUT)
            Case "Beer Out Temperature"
                tb3input.Text = DisplayInfo(DI_TEMP_BEER)
            Case "Aux 1 Temperature"
                tb3input.Text = DisplayInfo(DI_TEMP_AUX1)
            Case "Aux 2 Temperature"
                tb3input.Text = DisplayInfo(DI_TEMP_AUX2)
            Case "Steam(Pressure)"
                tb3input.Text = DisplayInfo(DI_STEAM_HEAT)
            Case "Raw HLT level"
                tb3input.Text = DisplayInfo(DI_RAW_HLT)
            Case "Raw Mash Tun level"
                tb3input.Text = DisplayInfo(DI_RAW_MASH)
            Case "Raw Kettle level"
                tb3input.Text = DisplayInfo(DI_RAW_KET)
        End Select

        Select Case My.Settings.as4input
            Case "Water In Temperature"
                tb4input.Text = DisplayInfo(DI_TEMP_H2O_IN)
            Case "Water Out Temperature"
                tb4input.Text = DisplayInfo(DI_TEMP_H2O_OUT)
            Case "Beer Out Temperature"
                tb4input.Text = DisplayInfo(DI_TEMP_BEER)
            Case "Aux 1 Temperature"
                tb4input.Text = DisplayInfo(DI_TEMP_AUX1)
            Case "Aux 2 Temperature"
                tb4input.Text = DisplayInfo(DI_TEMP_AUX2)
            Case "Steam(Pressure)"
                tb4input.Text = DisplayInfo(DI_STEAM_HEAT)
            Case "Raw HLT level"
                tb4input.Text = DisplayInfo(DI_RAW_HLT)
            Case "Raw Mash Tun level"
                tb4input.Text = DisplayInfo(DI_RAW_MASH)
            Case "Raw Kettle level"
                tb4input.Text = DisplayInfo(DI_RAW_KET)
        End Select

        Select Case My.Settings.as5input
            Case "Water In Temperature"
                tb5input.Text = DisplayInfo(DI_TEMP_H2O_IN)
            Case "Water Out Temperature"
                tb5input.Text = DisplayInfo(DI_TEMP_H2O_OUT)
            Case "Beer Out Temperature"
                tb5input.Text = DisplayInfo(DI_TEMP_BEER)
            Case "Aux 1 Temperature"
                tb5input.Text = DisplayInfo(DI_TEMP_AUX1)
            Case "Aux 2 Temperature"
                tb5input.Text = DisplayInfo(DI_TEMP_AUX2)
            Case "Steam(Pressure)"
                tb5input.Text = DisplayInfo(DI_STEAM_HEAT)
            Case "Raw HLT level"
                tb5input.Text = DisplayInfo(DI_RAW_HLT)
            Case "Raw Mash Tun level"
                tb5input.Text = DisplayInfo(DI_RAW_MASH)
            Case "Raw Kettle level"
                tb5input.Text = DisplayInfo(DI_RAW_KET)
        End Select

        lblStep.Text = DisplayInfo(DI_STEP_DESCR)
        'lblAlarm.Text = DisplayInfo(DI_ALARM_STATUS)
        'lblVlvProfile.Text = DisplayInfo(DI_AUTO_VLV_DESCR)
        'lblVlvProfile.Text = DisplayInfo(DI_VLV_PROF)
        lblHLThtr.Text = DisplayInfo(DI_HLT_HEAT)
        If lblHLThtr.Text = "OFF" Then
            lblHLThtr.BackColor = Color.GreenYellow
        ElseIf lblHLThtr.Text = "ON" Then
            lblHLThtr.BackColor = Color.Red
        Else
            lblHLThtr.BackColor = Color.LightPink
        End If
        lblMashHtr.Text = DisplayInfo(DI_MASH_HEAT)
        If lblMashHtr.Text = "OFF" Then
            lblMashHtr.BackColor = Color.GreenYellow
        ElseIf lblMashHtr.Text = "ON" Then
            lblMashHtr.BackColor = Color.Red
        Else
            lblMashHtr.BackColor = Color.LightPink
        End If
        lblKEThtr.Text = DisplayInfo(DI_KET_HEAT)
        If lblKEThtr.Text = "OFF" Then
            lblKEThtr.BackColor = Color.GreenYellow
        ElseIf lblKEThtr.Text = "ON" Then
            lblKEThtr.BackColor = Color.Red
        Else
            lblKEThtr.BackColor = Color.LightPink
        End If
        'lblSteamPressure.Text = DisplayInfo(DI_STEAM_HEAT)
        lblHLTset.Text = DisplayInfo(DI_HLT_SET)
        lblMashSet.Text = DisplayInfo(DI_MASH_SET)
        lblKetSet.Text = DisplayInfo(DI_KET_SET)
        'lblPgm.Text = DisplayInfo(DI_PGM_ID)
        lblTimer.Text = DisplayInfo(DI_TIME_VAL)
        lblTimer2.Text = DisplayInfo(DI_TIME_VAL2)
        'lblTimerStatus.Text = DisplayInfo(DI_TIME_STATUS)
        lblHLTlev.Text = DisplayInfo(DI_HLT_VOL)
        lblMashLev.Text = DisplayInfo(DI_MASH_VOL)
        lblKetLev.Text = DisplayInfo(DI_KET_VOL)


    End Sub

#End Region

#Region "Port Handler"

    Sub OpenComPort()

        'open port
        Try
            With comm
                comm.PortName = My.Settings.asComPort                    'Com port to use
                comm.Parity = "none"
                comm.StopBits = "one"
                comm.DataBits = "8"
                If IsNumeric(Me.cbBaudRate.Text) Then
                    comm.BaudRate = CInt(Me.cbBaudRate.Text)
                Else
                    comm.BaudRate = "9600"
                End If
                comm.DisplayWindowRx = Me.rtbDisplay
                comm.DisplayWindowTx = Me.rtbBTtx
                comm.OpenPort()
            End With

            'update status on BT screen
            tsslMiscInfo.Text = "waiting for BT ..."
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 2000
            tmrMessages.Enabled = True

            'ToolTip1.SetToolTip(pbBT2rem, "waiting for BT ...")
            'pbBT2rem.BackColor = Color.Orange

            rtbBTstatus.ForeColor = Color.OrangeRed
            rtbBTstatus.Text = "Waiting to connect to BT ..." + vbCrLf + vbCrLf
            rtbBTstatus.Text &= "If your BrewTroller is set to 'auto-reset', please wait a few seconds." + vbCrLf + vbCrLf
            rtbBTstatus.Text &= "NOTE: If the BT does not successfully connect, check your serial port setting and try again via the status bar drop-down list."

        Catch ex As Exception
            MsgBox("There was a problem opening the port." + Chr(13) + ex.Message + Chr(13))
            showBTcommProblem()
        End Try
    End Sub

    Sub CloseComPort()

        comm.ClosePort()

        'update status on BTremote
        tsslMiscInfo.Text = "BT connection closed ..."
        tsslMiscInfo.Visible = True
        tmrMessages.Interval = 10000
        tmrMessages.Enabled = True
        showBTdisconnected()
        rtbBTstatus.Text = "Not Connected: "
        rtbBTstatus.Text &= "Select serial port from the status"
        rtbBTstatus.Text &= "bar below and press 'connect' to begin. "

    End Sub

    Private Sub cboPort_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboPort.SelectedIndexChanged
        comm.PortName = cboPort.Text()
        SaveMySettings()
    End Sub

#End Region

#Region "XML"

    Sub manageXML()

        'handles local and remote xml data and support files
        If blnDoFTPupload Then
            'first FTPupload after installation, send remote support files
            If My.Settings.asBlnFTPsupportFilesOK = False Then
                Dim username As String = My.Settings.asFTPusername
                Dim URI As String = "http://www.brewtroller.com/btremote/" + username + "/"
                FTPUpload("BTpanel.htm")
                FTPUpload("BTpanel.jpg")
                FTPUpload("gauge.swf")
                My.Settings.asBlnFTPsupportFilesOK = True
            End If
            Call createXML(Application.StartupPath() + "\remoteBTdata.xml")   'creates xml file for remote upload
            Call XMLupload()    'uploads remote XML file
            blnDoFTPupload = False
        Else
            Call createXML(Application.StartupPath() + "\BTdata.xml") 'creates xml file for local display panel
        End If

    End Sub

    Sub createXML(ByVal strFileName As String)

        Dim url As String = "BTpanel.jpg"   'should be residing in application directory
        Dim width As Integer = 952
        Dim height As Integer = 661
        Dim xOffset_tunValues As Integer = 0
        Dim xOffset_tunGauges As Integer = 0
        Dim strValue As String = ""
        Dim strTun As String = "HLT"
        Dim needleVal As Single = 0
        Dim Value As Single
        Dim Rotate As Single    'angle of needle rotation: -147 = 5 degC; 0 = 55 deg C; 147 = 105 deg C
        Dim Level As Single     'level of sight-glass: 3 to 220 for 0-100%
        Dim volMax As Single = 60


        Dim settings As New XmlWriterSettings()
        settings.Indent = True
        settings.NewLineOnAttributes = True

        Try
            Using writer As XmlWriter = XmlWriter.Create(strFileName, settings)

                writer.WriteStartDocument()
                writer.WriteStartElement("gauge")
                writer.WriteStartElement("image")
                writer.WriteStartAttribute("url")
                writer.WriteValue(url)
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("width")
                writer.WriteValue(width)
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("height")
                writer.WriteValue(height)
                writer.WriteEndAttribute()
                writer.WriteEndElement()

                'loop through tun information
                For tun = 0 To 2

                    Select Case tun
                        Case 0  'HLT
                            'offsets are default values
                            strTun = "HLT"
                        Case 1  'Mash Tun
                            xOffset_tunValues = 119
                            xOffset_tunGauges = 314
                            strTun = "Mash Tun"
                        Case 2  'Kettle
                            xOffset_tunValues = 231
                            xOffset_tunGauges = 628
                    End Select

                    Select Case tun
                        Case 0  'HLT
                            strValue = lblHLTset.Text
                        Case 1  'Mash Tun
                            strValue = lblMashSet.Text
                        Case 2  'Kettle
                            strValue = lblKetSet.Text
                    End Select

                    writer.WriteComment(strTun & " Setpoint value")

                    'write text
                    writer.WriteStartElement("text")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunValues + 71))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("400")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("30")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("align")
                    writer.WriteValue("center")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("size")
                    writer.WriteValue("18")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("color")
                    writer.WriteValue("000000")
                    writer.WriteEndAttribute()
                    writer.WriteValue(strValue)
                    writer.WriteFullEndElement()

                    Select Case tun
                        Case 0  'HLT
                            If IsNumeric(DataInfo(DI_HLT_SET)) Then
                                Value = CSng(DataInfo(DI_HLT_SET))
                            Else
                                Value = 0
                            End If
                        Case 1  'Mash Tun
                            If IsNumeric(DataInfo(DI_MASH_SET)) Then
                                Value = CSng(DataInfo(DI_MASH_SET))
                            Else
                                Value = 0
                            End If
                        Case 2  'Kettle
                            If IsNumeric(DataInfo(DI_KET_SET)) Then
                                Value = CSng(DataInfo(DI_KET_SET))
                            Else
                                Value = 0
                            End If
                    End Select

                    writer.WriteComment(strTun & " Setpoint needle")

                    'no needle is shown if setpoint = 0 or is invalid
                    If Value <> 0 Then
                        If My.Settings.asBlnTempF Then
                            If Value <> 0 Then Value = CdegC(Value)
                        End If
                        'show needle
                        Rotate = (300 / 100 * (Value - 5)) - 150
                        'write needle information
                        writer.WriteStartElement("rotate")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue(CStr(xOffset_tunGauges + 169))
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("156")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("start")
                        writer.WriteValue(CStr(Rotate))
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("span")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("step")
                        writer.WriteValue("2")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("shake_frequency")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("shake_span")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("shadow_alpha")
                        writer.WriteValue("15")
                        writer.WriteEndAttribute()

                        'needle definition
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("000000")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("90")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue(CStr(xOffset_tunGauges + 168))
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("37")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue(CStr(xOffset_tunGauges + 170))
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("37")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue(CStr(xOffset_tunGauges + 170))
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("47")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue(CStr(xOffset_tunGauges + 168))
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("47")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteFullEndElement()    'end polygon
                        writer.WriteFullEndElement()    'end rotate

                    End If

                    'Temperature value
                    Select Case tun
                        Case 0  'HLT
                            strValue = lblHLTtemp.Text
                        Case 1  'Mash Tun
                            strValue = lblMashTemp.Text
                        Case 2  'Kettle
                            strValue = lblKetTemp.Text
                    End Select

                    writer.WriteComment(strTun & " Temperature value")

                    'write text
                    writer.WriteStartElement("text")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunValues + 71))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("450")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("30")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("align")
                    writer.WriteValue("center")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("size")
                    writer.WriteValue("18")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("color")
                    writer.WriteValue("ff0000")
                    writer.WriteEndAttribute()
                    writer.WriteValue(strValue)
                    writer.WriteFullEndElement()

                    'Temperature needle
                    Select Case tun
                        Case 0  'HLT
                            If IsNumeric(DataInfo(DI_HLT_TEMP)) Then
                                Value = CSng(DataInfo(DI_HLT_TEMP))
                            Else
                                Value = 0
                            End If
                        Case 1  'Mash Tun
                            If IsNumeric(DataInfo(DI_MASH_TEMP)) Then
                                Value = CSng(DataInfo(DI_MASH_TEMP))
                            Else
                                Value = 0
                            End If
                        Case 2  'Kettle
                            If IsNumeric(DataInfo(DI_KET_TEMP)) Then
                                Value = CSng(DataInfo(DI_KET_TEMP))
                            Else
                                Value = 0
                            End If
                    End Select

                    writer.WriteComment(strTun & " Temperature needle")

                    If My.Settings.asBlnTempF Then
                        If Value <> 0 Then Value = CdegC(Value)
                    End If

                    Rotate = (300 / 100 * (Value - 5)) - 150
                    'write needle information
                    writer.WriteStartElement("rotate")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 169))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("start")
                    writer.WriteValue(CStr(Rotate))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("span")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("step")
                    writer.WriteValue("2")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("shake_frequency")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("shake_span")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("shadow_alpha")
                    writer.WriteValue("15")
                    writer.WriteEndAttribute()

                    'needle circles
                    writer.WriteStartElement("circle")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 169))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("radius")
                    writer.WriteValue("8")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("ff6666")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("line_alpha")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("circle")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 169))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("radius")
                    writer.WriteValue("7")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("ff0000")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("line_alpha")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    'needle definition
                    writer.WriteStartElement("polygon")
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("ff0000")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("90")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("line_alpha")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 168))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("52")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 170))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("52")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 171))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 167))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()
                    writer.WriteFullEndElement()    'end polygon

                    writer.WriteFullEndElement()    'end rotate

                    'Level value
                    Select Case tun
                        Case 0  'HLT
                            strValue = lblHLTlev.Text
                        Case 1  'Mash Tun
                            strValue = lblMashLev.Text
                        Case 2  'Kettle
                            strValue = lblKetLev.Text
                    End Select

                    writer.WriteComment(strTun & " Level value")

                    'write text
                    writer.WriteStartElement("text")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunValues + 71))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("500")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("30")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("align")
                    writer.WriteValue("center")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("size")
                    writer.WriteValue("18")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("color")
                    writer.WriteValue("ff6600")
                    writer.WriteEndAttribute()
                    writer.WriteValue(strValue)
                    writer.WriteFullEndElement()

                    'Sight gauge
                    Select Case tun
                        Case 0  'HLT
                            volMax = CSng(My.Settings.asVolMaxHLT) / 1000
                            If volMax = 0 Then volMax = 100
                            If IsNumeric(DataInfo(DI_HLT_VOL)) Then
                                Level = -((DataInfo(DI_HLT_VOL) / volMax * (220 - 3)) + 3)
                            Else
                                Level = 0
                            End If
                        Case 1  'Mash Tun
                            volMax = CSng(My.Settings.asVolMaxMash) / 1000
                            If volMax = 0 Then volMax = 100
                            If IsNumeric(DataInfo(DI_MASH_VOL)) Then
                                Level = -((DataInfo(DI_MASH_VOL) / volMax * (220 - 3)) + 3)
                            Else
                                Level = 0
                            End If
                        Case 2  'Kettle
                            volMax = CSng(My.Settings.asVolMaxKet) / 1000
                            If volMax = 0 Then volMax = 100
                            If IsNumeric(DataInfo(DI_KET_VOL)) Then
                                Level = -((DataInfo(DI_KET_VOL) / volMax * (220 - 3)) + 3)
                            Else
                                Level = 0
                            End If
                    End Select

                    writer.WriteComment(strTun & " level sight-gauge")

                    writer.WriteStartElement("rect")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 29))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("275")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("9")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue(CStr(Level))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("ff6600")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("70")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    'Power value
                    Select Case tun
                        Case 0  'HLT
                            strValue = lblHLThtr.Text
                        Case 1  'Mash Tun
                            strValue = lblMashHtr.Text
                        Case 2  'Kettle
                            strValue = lblKEThtr.Text
                    End Select

                    writer.WriteComment(strTun & " Power value")

                    'write text
                    writer.WriteStartElement("text")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunValues + 71))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("550")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("30")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("align")
                    writer.WriteValue("center")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("size")
                    writer.WriteValue("18")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("color")
                    writer.WriteValue("3333cc")
                    writer.WriteEndAttribute()
                    writer.WriteValue(strValue)
                    writer.WriteFullEndElement()

                    'Power needle
                    Select Case tun
                        Case 0  'HLT
                            If IsNumeric(DataInfo(DI_HLT_HEAT)) Then
                                Value = CSng(DataInfo(DI_HLT_HEAT))
                            Else
                                Value = 0
                            End If
                        Case 1  'Mash Tun
                            If IsNumeric(DataInfo(DI_MASH_HEAT)) Then
                                Value = CSng(DataInfo(DI_MASH_HEAT))
                            Else
                                Value = 0
                            End If
                        Case 2  'Kettle
                            If IsNumeric(DataInfo(DI_KET_HEAT)) Then
                                Value = CSng(DataInfo(DI_KET_HEAT))
                            Else
                                Value = 0
                            End If
                    End Select

                    writer.WriteComment(strTun & " Power needle")

                    Rotate = (300 / 100 * (Value)) - 150

                    'write needle information
                    writer.WriteStartElement("rotate")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 169))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("start")
                    writer.WriteValue(CStr(Rotate))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("span")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("step")
                    writer.WriteValue("2")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("shake_frequency")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("shake_span")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("shadow_alpha")
                    writer.WriteValue("15")
                    writer.WriteEndAttribute()

                    'needle circles
                    writer.WriteStartElement("circle")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 169))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("radius")
                    writer.WriteValue("5")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("3333ff")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("line_alpha")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("circle")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 169))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("radius")
                    writer.WriteValue("4")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("3333cc")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("line_alpha")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    'needle definition
                    writer.WriteStartElement("polygon")
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("3333cc")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("90")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("line_alpha")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 168))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("112")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 170))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("112")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 171))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()

                    writer.WriteStartElement("point")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue(CStr(xOffset_tunGauges + 167))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("156")
                    writer.WriteEndAttribute()
                    writer.WriteEndElement()
                    writer.WriteFullEndElement()    'end polygon

                    writer.WriteFullEndElement()    'end rotate

                Next    'end of tuns loop

                'other inputs
                writer.WriteComment("Other Inputs - labels")
                Dim yValue As Integer = 350
                Dim strText As String = ""

                For inputNum = 1 To 5
                    Select Case inputNum
                        Case 1
                            strText = lbl1input.Text
                            strValue = tb1input.Text
                        Case 2
                            strText = lbl2input.Text
                            strValue = tb2input.Text
                        Case 3
                            strText = lbl3input.Text
                            strValue = tb3input.Text
                        Case 4
                            strText = lbl4input.Text
                            strValue = tb4input.Text
                        Case 5
                            strText = lbl5input.Text
                            strValue = tb5input.Text
                    End Select

                    writer.WriteStartElement("text")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue("425")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue(CStr(yValue + 1))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("75")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("30")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("align")
                    writer.WriteValue("right")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("size")
                    writer.WriteValue("14")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("color")
                    writer.WriteValue("3c3c3c")
                    writer.WriteEndAttribute()
                    writer.WriteValue(strText)
                    writer.WriteFullEndElement()

                    writer.WriteStartElement("text")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue("504")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue(CStr(yValue))
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("100")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("30")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("align")
                    writer.WriteValue("center")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("size")
                    writer.WriteValue("18")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("color")
                    writer.WriteValue("000000")
                    writer.WriteEndAttribute()
                    writer.WriteValue(strValue)
                    writer.WriteFullEndElement()

                    yValue += 50

                Next

                'write time - Mash
                writer.WriteComment("Time value - Mash")
                strValue = lblTimer.Text

                writer.WriteStartElement("text")
                writer.WriteStartAttribute("x")
                writer.WriteValue("594")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("y")
                writer.WriteValue("382")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("width")
                writer.WriteValue("280")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("height")
                writer.WriteValue("63")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("align")
                writer.WriteValue("center")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("size")
                writer.WriteValue("40")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("color")
                writer.WriteValue("ff0000")
                writer.WriteEndAttribute()
                writer.WriteValue(strValue)
                writer.WriteFullEndElement()

                'write timer status symbol
                'writer.WriteComment("Timer status symbol")
                ''rectangle common to all options
                'writer.WriteStartElement("rect")
                'writer.WriteStartAttribute("x")
                'writer.WriteValue("777")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("y")
                'writer.WriteValue("356")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("width")
                'writer.WriteValue("15")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("height")
                'writer.WriteValue("15")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("fill_color")
                'writer.WriteValue("ff6600")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("fill_alpha")
                'writer.WriteValue("50")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("color")
                'writer.WriteValue("ff0000")
                'writer.WriteEndAttribute()
                'writer.WriteFullEndElement()

                Select Case DisplayInfo(DI_TIME_STATUS)

                    Case "Paused"

                        'paused symbol
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("993300")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("777")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("782")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("782")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("777")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()
                        writer.WriteFullEndElement()    'end polygon

                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("993300")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("787")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("792")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("792")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("787")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()
                        writer.WriteFullEndElement()    'end polygon

                    Case "Stopped"

                        'stop symbol
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("ff0000")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("777")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("792")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("792")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("777")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()
                        writer.WriteFullEndElement()    'end polygon

                    Case "Running"

                        'running symbol
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("006600")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("777")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("777")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("792")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("363")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteFullEndElement()    'end polygon

                End Select

                'write time - Boil
                writer.WriteComment("Time value - Boil")
                strValue = lblTimer2.Text

                writer.WriteStartElement("text")
                writer.WriteStartAttribute("x")
                writer.WriteValue("734")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("y")
                writer.WriteValue("382")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("width")
                writer.WriteValue("280")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("height")
                writer.WriteValue("63")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("align")
                writer.WriteValue("center")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("size")
                writer.WriteValue("40")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("color")
                writer.WriteValue("ff0000")
                writer.WriteEndAttribute()
                writer.WriteValue(strValue)
                writer.WriteFullEndElement()

                'write timer status symbol
                'writer.WriteComment("Timer status symbol")
                ''rectangle common to all options
                'writer.WriteStartElement("rect")
                'writer.WriteStartAttribute("x")
                'writer.WriteValue("777")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("y")
                'writer.WriteValue("356")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("width")
                'writer.WriteValue("15")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("height")
                'writer.WriteValue("15")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("fill_color")
                'writer.WriteValue("ff6600")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("fill_alpha")
                'writer.WriteValue("50")
                'writer.WriteEndAttribute()
                'writer.WriteStartAttribute("color")
                'writer.WriteValue("ff0000")
                'writer.WriteEndAttribute()
                'writer.WriteFullEndElement()

                Select Case DisplayInfo(DI_TIME_STATUS2)

                    Case "Paused"

                        'paused symbol
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("993300")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("917")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("922")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("922")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("917")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()
                        writer.WriteFullEndElement()    'end polygon

                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("993300")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("927")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("932")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("932")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("927")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()
                        writer.WriteFullEndElement()    'end polygon

                    Case "Stopped"

                        'stop symbol
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("ff0000")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("917")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("932")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("932")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("917")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()
                        writer.WriteFullEndElement()    'end polygon

                    Case "Running"

                        'running symbol
                        writer.WriteStartElement("polygon")
                        writer.WriteStartAttribute("fill_color")
                        writer.WriteValue("006600")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("fill_alpha")
                        writer.WriteValue("100")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("line_alpha")
                        writer.WriteValue("0")
                        writer.WriteEndAttribute()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("917")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("356")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("917")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("371")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteStartElement("point")
                        writer.WriteStartAttribute("x")
                        writer.WriteValue("932")
                        writer.WriteEndAttribute()
                        writer.WriteStartAttribute("y")
                        writer.WriteValue("363")
                        writer.WriteEndAttribute()
                        writer.WriteEndElement()

                        writer.WriteFullEndElement()    'end polygon

                End Select

                'write step
                writer.WriteComment("Step value")
                strValue = lblStep.Text
                writer.WriteStartElement("text")
                writer.WriteStartAttribute("x")
                writer.WriteValue("683")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("y")
                writer.WriteValue("450")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("width")
                writer.WriteValue("250")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("height")
                writer.WriteValue("30")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("align")
                writer.WriteValue("center")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("size")
                writer.WriteValue("18")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("color")
                writer.WriteValue("000000")
                writer.WriteEndAttribute()
                writer.WriteValue(strValue)
                writer.WriteFullEndElement()

                'write BrewTroller Info
                writer.WriteComment("BrewTroller Info")
                strValue = rtbBTstatus.Text
                writer.WriteStartElement("text")
                writer.WriteStartAttribute("x")
                writer.WriteValue("683")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("y")
                writer.WriteValue("550")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("width")
                writer.WriteValue("250")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("height")
                writer.WriteValue("30")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("align")
                writer.WriteValue("center")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("size")
                writer.WriteValue("12")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("color")
                writer.WriteValue("000000")
                writer.WriteEndAttribute()
                writer.WriteValue(strValue)
                writer.WriteFullEndElement()

                'write status bar
                writer.WriteComment("Status bar")
                strValue = tsslSerialMsg.Text & "  " & tsslCom.Text & "  " & tsslLogMsg.Text & " "
                strValue &= tsslFTPmsg.Text & "  " & tsslBTprogram.Text & "  "
                strValue &= tsslBTstep.Text & "  " & tsslBTvalveProfile.Text & "  " & tsslBTalarm.Text
                writer.WriteStartElement("text")
                writer.WriteStartAttribute("x")
                writer.WriteValue("20")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("y")
                writer.WriteValue("617")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("width")
                writer.WriteValue("673")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("height")
                writer.WriteValue("30")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("align")
                writer.WriteValue("left")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("size")
                writer.WriteValue("15")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("color")
                writer.WriteValue("000000")
                writer.WriteEndAttribute()
                writer.WriteValue(strValue)
                writer.WriteFullEndElement()

                'give visual indication if BT is not connected
                If tsslSerialMsg.Text <> "BT OK" Then
                    writer.WriteComment("Showing panel disabled - BT not connected")
                    writer.WriteStartElement("rect")
                    writer.WriteStartAttribute("x")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("y")
                    writer.WriteValue("0")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("width")
                    writer.WriteValue("952")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("height")
                    writer.WriteValue("661")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_color")
                    writer.WriteValue("999999")
                    writer.WriteEndAttribute()
                    writer.WriteStartAttribute("fill_alpha")
                    writer.WriteValue("50")
                    writer.WriteEndAttribute()
                    writer.WriteFullEndElement()
                End If

                'add update
                writer.WriteStartElement("update")
                writer.WriteStartAttribute("url")
                writer.WriteValue(Application.StartupPath() + "\BTdata.xml")
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("delay")
                If strFileName = Application.StartupPath() + "\remoteBTdata.xml" Then
                    'we need a 20 second delay
                    writer.WriteValue("20")
                Else
                    'set local update to immediate
                    writer.WriteValue("0")
                End If
                writer.WriteEndAttribute()
                writer.WriteStartAttribute("delay_type")
                writer.WriteValue("1")
                writer.WriteEndAttribute()

                writer.WriteEndDocument()
                writer.Flush()
            End Using

        Catch ex As Exception
            'show error on BT screen
            If Err.Number = 5 Then
                Dim strMsg As String
                strMsg = "You do not have sufficient file access permissions to create files needed for BTremote." + vbCrLf + vbCrLf
                strMsg &= "Try one of the following to fix the issue:" + vbCrLf
                strMsg &= "1. Right-click the BTremote exe file, select properties, compatibility, XP SP3" + vbCrLf
                strMsg &= "2. Right-click the BTremote exe file, select 'Run as administrator'" + vbCrLf
                strMsg &= "3. For Vista users: follow advice at http://www.computerperformance.co.uk/vista/vista_administrator_activate.htm" + vbCrLf
                strMsg &= "4. For Win7 users: follow advice at http://www.computerperformance.co.uk/windows7/windows7_activate_administrator.htm"

                MsgBox(strMsg)
            End If
            tsslMiscInfo.Text = "CreateXMLerr: " + Err.Number.ToString
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 1000
            tmrMessages.Enabled = True
        End Try


    End Sub

    Sub HTMLswitch(ByVal swData As Double)
        If swData = 1 Then
            PrintLine(1, "<td bgcolor=#CCFF66><center>ON</center></td>")
        Else
            PrintLine(1, "<td bgcolor=#FF9999><center>OFF</center></td>")
        End If
    End Sub

    Sub HTMLtemp(ByVal tempVal)

        PrintLine(1, "<td bgcolor=#CCCCFF><center>" + Format(tempVal, "#.0") + Chr(176) + strDegreeNotation + "</center></td>")

    End Sub

    Sub HTMLset(ByVal tempVal)

        PrintLine(1, "<td bgcolor=#FFCCCC><center>" + Format(tempVal, "#.0") + Chr(176) + strDegreeNotation + "</center></td>")

    End Sub

#End Region

#Region "Comms from BrewTroller"

    Private Sub rtbDisplay_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rtbDisplay.TextChanged
        'If rtbDisplay.TextLength > 50 Then
        '    If tsslSerialMsg.Text <> "BT OK" Then
        '        showBTconnected()
        '    End If
        'End If

        Call DecodeSerialData()

    End Sub

    Private Sub showBTconnected()

        If blnAllowSerial = False Then
            'Show we have now successfully connected
            tsslSerialMsg.Text = "BT OK"
            tsslLogMsg.Text = "Log on"
            'pbBT2rem.BackColor = Color.GreenYellow
            btnGetRecipeFromBT.Enabled = True
            btnSendRecipeToBT.Enabled = True
            cboBTrecipeSlot.Enabled = True
            gbMenuControl.Enabled = True
            tmrSendtoBT.Enabled = True    'opens the transmit timer queue
            btnSend.Enabled = True
            cbGoLive.Enabled = True
            tsslBTalarm.Enabled = True
            tsslBTprogram.Enabled = True
            tsslBTstep.Enabled = True
            tsslBTtemp.Enabled = True
            tsslBTmashTimer.Enabled = True
            tsslBTboilTimer.Enabled = True
            tsslBTvalveProfile.Enabled = True
            serialOKtime = Now
            'gbDials.Enabled = True
            gbTuns.Enabled = True
            gbOtherInputs.Enabled = True
            gbStepAndTime.Enabled = True
            gbStepControl.Enabled = True
            CommandToolStripMenuItem.Enabled = True
            blnAllowSerial = True
            Me.CommandToolStripMenuItem.Enabled = True
            Me.ControlToolStripMenuItem.Enabled = True

            'for BTremote to work with the brewtroller, we need BT logging to be activated
            AddToTXstack("SET_LOGSTATUS+1-")

            If DisplayInfo(DI_VER) = "" Then
                'we don't have version or build information, perform a soft reset if requested by user
                If cbReset.Checked = True Then
                    AddToTXstack("RESET+1-")
                Else
                    If Settings.asBTversion = "BT2" Then
                        DisplayInfo(DI_VER) = "2.x"
                        DisplayInfo(DI_BUILD) = "unknown"
                    ElseIf Settings.asBTversion = "BT1" Then
                        DisplayInfo(DI_VER) = "1.x"
                        DisplayInfo(DI_BUILD) = "unknown"
                    ElseIf Settings.asBTversion = "FT" Then
                        DisplayInfo(DI_VER) = "FT"
                        DisplayInfo(DI_BUILD) = "unknown"
                    End If
                    showBuildInfo()
                End If
            Else
                showBuildInfo()
            End If

            'Add start up commands to transmit buffer
            If Settings.asBTversion = "BT1" Then
                'get program settings
                For i = 0 To 29
                    'requests for program recipes
                    AddToTXstack("GET_PROG+" + Str(i) + "-")
                Next
                If blnGetABrecipe = True Then
                    AddToTXstack("GET_ABSET-")
                End If
                If My.Settings.asVolMaxHLT = "0" Then
                    AddToTXstack("GET_VSET+0-") 'get volume settings
                End If
                If My.Settings.asVolMaxMash = "0" Then
                    AddToTXstack("GET_VSET+1-") 'get volume settings
                End If
                If My.Settings.asVolMaxKet = "0" Then
                    AddToTXstack("GET_VSET+2-") 'get volume settings
                End If
            ElseIf Settings.asBTversion = "BT2" Then
                AddToTXstack("SET_LOGSTATUS+1-")    'Ensure BT sends serial messages
                'get program settings
                For i = 0 To 19
                    'requests for program recipes
                    AddToTXstack("GET_PROG+" + Str(i) + "-")
                Next
                AddToTXstack("GET_VSET+0-") 'get volume settings
                AddToTXstack("GET_VSET+1-") 'get volume settings
                AddToTXstack("GET_VSET+2-") 'get volume settings
                For i = 0 To 8
                    'Get onewire address of each temp sensor
                    AddToTXstack("GET_TS+" + Str(i) + "-")
                Next

                'get valve profile settings
                AddToTXstack("GET_VLVCFG+0-")
                AddToTXstack("GET_VLVCFG+1-")
                AddToTXstack("GET_VLVCFG+2-")
                AddToTXstack("GET_VLVCFG+3-")
                AddToTXstack("GET_VLVCFG+4-")
                AddToTXstack("GET_VLVCFG+5-")
                AddToTXstack("GET_VLVCFG+6-")
                AddToTXstack("GET_VLVCFG+7-")
                AddToTXstack("GET_VLVCFG+8-")
                AddToTXstack("GET_VLVCFG+9-")
                AddToTXstack("GET_VLVCFG+10-")
                AddToTXstack("GET_VLVCFG+11-")
                AddToTXstack("GET_VLVCFG+12-")

                'get output settings
                AddToTXstack("GET_OSET+0-")
                AddToTXstack("GET_OSET+1-")
                AddToTXstack("GET_OSET+2-")
                AddToTXstack("GET_OSET+3-")

            ElseIf Settings.asBTversion = "FT" Then
                'add settings requests here
            End If


        End If

    End Sub

    Private Sub showBuildInfo()
        'show version and build information
        Dim strStatus As String
        strStatus = "BrewTroller version: " & DisplayInfo(DI_VER) & ", build: " & DisplayInfo(DI_BUILD) & vbCrLf
        strStatus &= "www.brewtroller.com" & vbCrLf & vbCrLf
        rtbBTstatus.Text = strStatus
        rtbBTstatus.ForeColor = Color.Black
        Me.Text = "BTremote for BrewTroller " & DisplayInfo(DI_VER)

    End Sub
    Private Sub showBTdisconnected()
        tsslLogMsg.Text = "No Log"
        tsslSerialMsg.Text = "BT NC"
        'pbBT2rem.BackColor = Color.DarkGray
        btnGetRecipeFromBT.Enabled = False
        btnSendRecipeToBT.Enabled = False
        cboBTrecipeSlot.Enabled = False
        gbMenuControl.Enabled = False
        tmrSendtoBT.Enabled = False    'closes the transmit timer queue
        btnSend.Enabled = False
        cbGoLive.Enabled = False
        tsslBTalarm.Enabled = False
        tsslBTprogram.Enabled = False
        tsslBTstep.Enabled = False
        tsslBTtemp.Enabled = False
        tsslBTmashTimer.Enabled = False
        tsslBTboilTimer.Enabled = False
        tsslBTvalveProfile.Enabled = False
        'gbDials.Enabled = False
        gbTuns.Enabled = False
        gbOtherInputs.Enabled = False
        gbStepAndTime.Enabled = False
        gbStepControl.Enabled = False
        CommandToolStripMenuItem.Enabled = False

    End Sub

    Private Sub showBTcommProblem()

        tsslSerialMsg.Text = "BT ALM"
        'pbBT2rem.BackColor = Color.Red
        btnGetRecipeFromBT.Enabled = False
        btnSendRecipeToBT.Enabled = False
        cboBTrecipeSlot.Enabled = False
        gbMenuControl.Enabled = False
        tmrSendtoBT.Enabled = False    'opens the transmit timer queue
        btnSend.Enabled = False
        cbGoLive.Enabled = False
        tsslBTalarm.Enabled = False
        tsslBTprogram.Enabled = False
        tsslBTstep.Enabled = False
        tsslBTtemp.Enabled = False
        tsslBTmashTimer.Enabled = False
        tsslBTvalveProfile.Enabled = False
        'gbDials.Enabled = False
        gbTuns.Enabled = False
        gbOtherInputs.Enabled = False
        gbStepAndTime.Enabled = False

    End Sub

    Private Sub decodeBT1data(ByVal SO As Array)
        Select Case SO(SER_CLASS)
            Case "AB"
                'Autobrew class

                Select Case SO(SER_MSG)
                    Case "START"
                        If IsNumeric(SO(SER_TIME)) Then
                            TimeStamp(TS_AB_START_TIME) = SO(SER_TIME)
                            DisplayInfo(DI_STEP_DESCR) = "Auto brew started at " + Str(SO(SER_TIME))
                        End If
                    Case "SETTINGS"
                        'dump of all autobrew settings

                    Case Else

                End Select

            Case "CMD"
                'Command Class

                Select Case SO(SER_MSG)
                    Case "BAD_PARAM"
                        'Indicates a parameter to a command was rejected
                        tsslMiscInfo.Text = "BT BAD_PARAM " + SO(3) + " " + SO(4)
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case "MSG_OVERFLOW"
                        'Exceeded max number of input fields (20)

                    Case "FIELD_OVERFLOW"
                        'Exceeded mas number of chars in command field (20)

                    Case "UNKNOWN_CMD"
                        'Invalid command
                        tsslMiscInfo.Text = "BT UNKNOWN_CMD " + SO(3) + " " + SO(4)
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case Else

                End Select


            Case "DATA"
                'Data class
                Select Case SO(SER_MSG)
                    Case "AB_STEP"
                        Call SerABstep(SO(STEP_ID))
                    Case "ALARM"
                        Call SerDatAlm(SO(ALM_STATUS))
                    Case "AUTOVLV"
                        Call SerAutoVlv(SO(AUTO_VLV_STATUS))

                    Case "HEATPWR"
                        Call SerHeatPwr(SO(TUN_ID), SO(DATA_VAL))

                    Case "PGM"
                        Call serPgm(SO(PROG_ID))

                    Case "SETPOINT"
                        Call SerSetPoint(SO(TUN_ID), SO(DATA_VAL), SO(TEMP_UNIT))

                    Case "SETVLV"
                        'Call SerDatVlv(SO(VALVE_BITS))

                    Case "STEAM"
                        '*** need to code this in

                    Case "TEMP"
                        Call SerDatTemp(SO(TEMP_ID), SO(TEMP_VAL), SO(TEMP_UNIT))

                    Case "TIMER"
                        Call serTimer("BT1", SO(TIME_LEFT), SO(TIMER_STATUS))

                    Case "VOL"
                        Call serDatVol(SO(VOL_ID), SO(VOL_VAL), SO(VOL_UNIT))

                    Case "VLVPRF"
                        Call serDatVlvProf(SO(VLV_PROFILE_MASK))

                End Select

            Case "DEBUG"
                'Debug Class

                'Ensure RX tab is visible

                Select Case SO(SER_MSG)
                    Case "CFG_VER"
                        'Eeprom configuration data

                    Case "VOL_READ"
                        'detailed volume settings
                        If IsNumeric(SO(DATA_VAL)) Then

                            Select Case SO(TUN_ID)
                                Case "0"
                                    'HLT raw data
                                    DataInfo(DI_RAW_HLT) = SO(DATA_VAL)
                                    DisplayInfo(DI_RAW_HLT) = SO(DATA_VAL)
                                    If IsNumeric(SO(DATA_VAL)) Then
                                        If My.Settings.asBlnLogNow Then listHLTvolRaw.Add(Now.ToOADate, CDbl(SO(DATA_VAL)))
                                    End If
                                Case "1"
                                    'Mash raw data
                                    DataInfo(DI_RAW_MASH) = SO(DATA_VAL)
                                    DisplayInfo(DI_RAW_MASH) = SO(DATA_VAL)
                                    If IsNumeric(SO(DATA_VAL)) Then
                                        If My.Settings.asBlnLogNow Then listMashVolRaw.Add(Now.ToOADate, CDbl(SO(DATA_VAL)))
                                    End If
                                Case "2"
                                    'Mash raw data
                                    DataInfo(DI_RAW_KET) = SO(DATA_VAL)
                                    DisplayInfo(DI_RAW_KET) = SO(DATA_VAL)
                                    If IsNumeric(SO(DATA_VAL)) Then
                                        If My.Settings.asBlnLogNow Then listMashVolRaw.Add(Now.ToOADate, CDbl(SO(DATA_VAL)))
                                    End If
                                Case Else

                            End Select

                        End If
                End Select

            Case "GLOBAL"
                'global class

                Select Case SO(SER_MSG)
                    Case "PROG_SET"
                        'saved recipe
                        Dim Prog_set(29) As String
                        For i = PS_PROG_NUM To PS_GRAIN_TEMP
                            Prog_set(i - 3) = SO(i)
                        Next

                        If blnLoadBTrecipe = True And intLoadBTrecipeNum = SO(PS_PROG_NUM) + 1 Then
                            'we want to load these recipe values onto our session screen
                            tbRecipeName.Text = SO(PS_PROG_NAME)
                            tbDoughIn.Text = SO(PS_DI_TEMP)
                            tbDoughTime.Text = SO(PS_DI_MINS)
                            tbProteinTemp.Text = SO(PS_PROTEIN_TEMP)
                            tbProteinTime.Text = SO(PS_PROTEIN_MINS)
                            tbSacchTemp.Text = SO(PS_SACCH_TEMP)
                            tbSacchTime.Text = SO(PS_SACCH_MINS)
                            tbMOtemp.Text = SO(PS_MO_TEMP)
                            tbMOtime.Text = SO(PS_MO_MINS)
                            tbSpargeTemp.Text = SO(PS_SPARGE_TEMP)
                            tbDelay.Text = SO(PS_DELAY_MINS)
                            tbHLsetpoint.Text = SO(PS_HLT_SET)
                            tbVol.Text = SO(PS_BATCH_VOL)
                            tbGrainWeight.Text = SO(PS_GRAIN_WGT)
                            tbBoilTotal.Text = SO(PS_BOIL_MINS)
                            tbMashRatio.Text = SO(PS_MASH_RATIO)
                            tbPitchTemp.Text = SO(PS_PITCH_TEMP)
                            tbHLsetpoint.Text = SO(PS_HLT_SET)
                            Dim intAddns As Integer = SO(PS_BOIL_ADDNS)
                            getAddns(intAddns)
                            tbGrainTemp.Text = SO(PS_GRAIN_TEMP)
                            blnLoadBTrecipe = False 'recipe data loaded

                        End If

                        'update recipe slot name with received data
                        If SO(PS_PROG_NAME) <> "" Then
                            cboBTrecipeSlot.Items.RemoveAt(SO(PS_PROG_NUM) + 1)
                            cboBTrecipeSlot.Items.Insert(SO(PS_PROG_NUM) + 1, SO(PS_PROG_NAME))
                            cboBTrecipeSlot.Text = SO(PS_PROG_NAME)
                        End If
                    Case "AB_SET"
                        'we will load these values directly onto the session screen
                        tbRecipeName.Text = "** Current Autobrew settings **"
                        tbDoughIn.Text = SO(PS_DI_TEMP - 2)
                        tbDoughTime.Text = SO(PS_DI_MINS - 2)
                        tbProteinTemp.Text = SO(PS_PROTEIN_TEMP - 2)
                        tbProteinTime.Text = SO(PS_PROTEIN_MINS - 2)
                        tbSacchTemp.Text = SO(PS_SACCH_TEMP - 2)
                        tbSacchTime.Text = SO(PS_SACCH_MINS - 2)
                        tbMOtemp.Text = SO(PS_MO_TEMP - 2)
                        tbMOtime.Text = SO(PS_MO_MINS - 2)
                        tbSpargeTemp.Text = SO(PS_SPARGE_TEMP - 2)
                        tbDelay.Text = SO(PS_DELAY_MINS - 2)
                        tbHLsetpoint.Text = SO(PS_HLT_SET - 2)
                        tbVol.Text = SO(PS_BATCH_VOL - 2)
                        tbGrainWeight.Text = SO(PS_GRAIN_WGT - 2)
                        tbBoilTotal.Text = SO(PS_BOIL_MINS - 2)
                        tbMashRatio.Text = SO(PS_MASH_RATIO - 2)
                        tbPitchTemp.Text = SO(PS_PITCH_TEMP - 2)
                        tbHLsetpoint.Text = SO(PS_HLT_SET - 2)
                        Dim intAddns As Integer = SO(PS_BOIL_ADDNS - 2)
                        getAddns(intAddns)
                        tbGrainTemp.Text = SO(PS_GRAIN_TEMP - 2)
                        blnLoadBTrecipe = False 'recipe data loaded
                        cboBTrecipeSlot.Text = "**Autobrew**"

                    Case "VOL_SET"
                        Select Case SO(3)
                            Case "0"
                                tbHLTmax.Enabled = True
                                tbHLTmax.TabIndex = SO(4)
                                tbHLTmax.Enabled = False
                                My.Settings.asVolMaxHLT = SO(4)
                            Case "1"
                                tbMashMax.Enabled = True
                                tbMashMax.TabIndex = SO(4)
                                tbMashMax.Enabled = False
                                My.Settings.asVolMaxMash = SO(4)
                            Case "2"
                                tbKetMax.Enabled = True
                                tbKetMax.TabIndex = SO(4)
                                tbKetMax.Enabled = False
                                My.Settings.asVolMaxKet = SO(4)
                        End Select

                End Select

            Case "MENU"
                'Menu Class

                Select Case SO(SER_MSG)
                    Case "CONFIRM_DEL"
                        'delete action has been triggered and ids prompt choice options
                        'lblMenuTitle.Text = "Confirmation required"
                        'cboMenuOptions.Items.Clear()
                        'cboMenuOptions.Items.Add("Confirm Delete?")
                        'cboMenuOptions.SelectedIndex = cboMenuOptions.FindString("Confirm Delete?")
                        'btnSelect.Text = "Delete"
                        'btnSelect.ForeColor = Color.OrangeRed

                    Case "CONFIRM_EXIT"
                        'exit action has been triggered and ids propmpt choice opitons
                        'lblMenuTitle.Text = "Confirmation required"
                        'cboMenuOptions.Items.Clear()
                        'cboMenuOptions.Items.Add("Confirm Exit?")
                        'cboMenuOptions.SelectedIndex = cboMenuOptions.FindString("Confirm Exit?")
                        'btnSelect.Text = "Exit"
                        'btnSelect.ForeColor = Color.DarkRed

                    Case "PROMPT"
                        'indicates menu choices

                        'reenable menu options on form
                        'btnSelect.Enabled = True
                        'cboMenuOptions.Enabled = True

                        Dim strMenuTitle As String
                        Dim intMenuOptions As Integer

                        strMenuTitle = SO(MENU_TITLE)
                        intMenuOptions = SO(MENU_OPTIONS)
                        Dim strMenuOpions(intMenuOptions)
                        'cboMenuOptions.Items.Clear()

                        strMenuTitle = StrConv(strMenuTitle, VbStrConv.ProperCase)
                        'lblMenuTitle.Text = strMenuTitle

                        'If intMenuOptions = 0 Then
                        '    cboMenuOptions.Items.Add(strMenuTitle)
                        '    cboMenuOptions.SelectedIndex = cboMenuOptions.FindString(strMenuTitle)
                        '    btnSelect.Text = "Continue"
                        '    btnSelect.ForeColor = Color.DarkRed
                        'Else
                        '    For i = 0 To intMenuOptions
                        '        cboMenuOptions.Items.Add(SO(i + 5))
                        '    Next
                        '    cboMenuOptions.SelectedItem = 0
                        '    cboMenuOptions.SelectedIndex = cboMenuOptions.FindString(SO(5))
                        '    btnSelect.Text = "Select Choice"
                        '    btnSelect.ForeColor = Color.Blue
                        'End If

                    Case "RESULT"
                        'menu closed and result returned

                    Case "SELECT"
                        'option selected

                    Case Else

                End Select

            Case "SYSTEM"
                'System Class

                Select Case SO(SER_MSG)
                    Case "VER"
                        'brewTroller firmware version and build information
                        Dim strVerNum As String
                        Dim strBuildNum As String

                        'read version and build numbers
                        strVerNum = SO(VER_NUM)
                        strBuildNum = SO(BUILD_NUM)

                        'generate BTstatus string
                        Dim strStatus As String
                        strStatus = "BrewTroller version: " & strVerNum & ", build: " & strBuildNum & vbCrLf
                        strStatus &= "www.brewtroller.com" & vbCrLf & vbCrLf
                        rtbBTstatus.Text = strStatus
                        rtbBTstatus.ForeColor = Color.Black
                    Case Else

                End Select
            Case Else
                '

        End Select

    End Sub

    Private Sub decodeBT2data(ByVal SO As Array)

        Select Case SO(SER_CLASS)
            Case "GLOBAL"
                Select Case SO(SER_MSG)
                    Case "OUTPUT_SET"
                        'output settings
                        Dim intItem As Integer = 0
                        Try
                            intItem = 6 * CInt(SO(OUTPUT_ID)) + DI_HLT_OP_MODE
                            DisplayInfo(intItem) = SO(OUTPUT_MODE)
                            DisplayInfo(intItem + 1) = SO(OUTPUT_CYCLE)
                            DisplayInfo(intItem + 2) = SO(OUTPUT_P_GAIN)
                            DisplayInfo(intItem + 3) = SO(OUTPUT_I_GAIN)
                            DisplayInfo(intItem + 4) = SO(OUTPUT_D_GAIN)
                            DisplayInfo(intItem + 5) = SO(OUTPUT_HYST)
                        Catch ex As Exception

                        End Try
                    Case "VLV_PROFILE"
                        'indicates specified valve profile
                        Dim strValveBits As Integer = 0
                        strValveBits = SO(VALVE_BITS2)
                        Select Case SO(VALVE_PROFILE2)
                            Case "0"
                                Settings.VPfillHLT = strValveBits
                            Case "1"
                                Settings.VPfillMash = strValveBits
                            Case "2"
                                Settings.VPaddGrain = strValveBits
                            Case "3"
                                Settings.VPmashHeat = strValveBits
                            Case "4"
                                Settings.VPmashIdle = strValveBits
                            Case "5"
                                Settings.VPspargeIn = strValveBits
                            Case "6"
                                Settings.VPspargeOut = strValveBits
                            Case "7"
                                Settings.VPboilAddition = strValveBits
                            Case "8"
                                Settings.VPkettleLid = strValveBits
                            Case "9"
                                Settings.VPchillerWater = strValveBits
                            Case "10"
                                Settings.VPchillerBeer = strValveBits
                            Case "11"
                                Settings.VPboilRecirc = strValveBits
                            Case "12"
                                Settings.VPdrain = strValveBits
                        End Select
                    Case "TS_ADDR"
                        'one wire address of temperature sensors
                        Dim strAddress As String = ""
                        For i = TS_ADDR_B0 To TS_ADDR_B7
                            'retrieve each byte
                            strAddress &= Format(CInt(SO(i)), "000")
                        Next
                        'and update DisplayInfo
                        If IsNumeric(SO(TEMP_ID)) Then
                            Dim intUpdate As Integer
                            intUpdate = CInt(SO(TEMP_ID)) + DI_TS_HLT
                            DisplayInfo(intUpdate) = strAddress
                        End If
                    Case "TS_SCAN"
                        'indicates address of unassigned temperature sensor
                        'check to see which sensor we wish to assign this address to
                        Dim strMsg As String = "SET_TS+"
                        If blnAssignTS_SCAN_to_0 Then
                            strMsg &= "0+"
                            blnAssignTS_SCAN_to_0 = False
                        ElseIf blnAssignTS_SCAN_to_1 Then
                            strMsg &= "1+"
                            blnAssignTS_SCAN_to_1 = False
                        ElseIf blnAssignTS_SCAN_to_2 Then
                            strMsg &= "2+"
                            blnAssignTS_SCAN_to_2 = False
                        ElseIf blnAssignTS_SCAN_to_3 Then
                            strMsg &= "3+"
                            blnAssignTS_SCAN_to_3 = False
                        ElseIf blnAssignTS_SCAN_to_4 Then
                            strMsg &= "4+"
                            blnAssignTS_SCAN_to_4 = False
                        ElseIf blnAssignTS_SCAN_to_5 Then
                            strMsg &= "5+"
                            blnAssignTS_SCAN_to_5 = False
                        ElseIf blnAssignTS_SCAN_to_6 Then
                            strMsg &= "6+"
                            blnAssignTS_SCAN_to_6 = False
                        ElseIf blnAssignTS_SCAN_to_7 Then
                            strMsg &= "7+"
                            blnAssignTS_SCAN_to_7 = False
                        ElseIf blnAssignTS_SCAN_to_8 Then
                            strMsg &= "8+"
                            blnAssignTS_SCAN_to_8 = False
                        End If
                        If strMsg <> "SET_TS+" Then
                            'we are assigning an probe to a specific address
                            strMsg &= SO(TS_ADDR_B0 - 1) & "+" & SO(TS_ADDR_B1 - 1) & "+" & SO(TS_ADDR_B2 - 1) & _
                                     "+" & SO(TS_ADDR_B3 - 1) & "+" & SO(TS_ADDR_B4 - 1) & "+" + SO(TS_ADDR_B5 - 1) & "+" _
                                     & SO(TS_ADDR_B6 - 1) & "+" & SO(TS_ADDR_B7 - 1) & "-"
                            AddToTXstack(strMsg)
                        End If

                    Case "PROG_SET"
                        'saved recipe
                        Dim Prog_set(29) As String
                        For i = PS2_PROG_NUM To PS2_PROG_UNIT
                            Prog_set(i - 3) = SO(i)
                        Next

                        If blnLoadBTrecipe = True And intLoadBTrecipeNum = SO(PS2_PROG_NUM) Then
                            'we want to load these recipe values onto our session screen
                            tbRecipeName.Text = SO(PS2_PROG_NAME)
                            tbDoughIn.Text = SO(PS2_DI_TEMP)
                            tbDoughTime.Text = SO(PS2_DI_MINS)
                            tb2AcidTemp.Text = SO(PS2_ACID_TEMP)
                            tb2AcidTime.Text = SO(PS2_ACID_MINS)
                            tbProteinTemp.Text = SO(PS2_PROTEIN_TEMP)
                            tbProteinTime.Text = SO(PS2_PROTEIN_MINS)
                            tbSacchTemp.Text = SO(PS2_SACCH_TEMP)
                            tbSacchTime.Text = SO(PS2_SACCH_MINS)
                            tb2Sacch2Temp.Text = SO(PS2_SACCH2_TEMP)
                            tb2Sacch2Time.Text = SO(PS2_SACCH2_MINS)
                            tbMOtemp.Text = SO(PS2_MO_TEMP)
                            tbMOtime.Text = SO(PS2_MO_MINS)
                            tbSpargeTemp.Text = SO(PS2_SPARGE_TEMP)
                            'tbDelay.Text = SO(PS_DELAY_MINS) - not used in BT2
                            tbHLsetpoint.Text = SO(PS2_HLT_SET)
                            tbVol.Text = SO(PS2_BATCH_VOL)
                            tbGrainWeight.Text = SO(PS2_GRAIN_WGT)
                            tbBoilTotal.Text = SO(PS2_BOIL_MINS)
                            tbMashRatio.Text = SO(PS2_MASH_RATIO)
                            tbPitchTemp.Text = SO(PS2_PITCH_TEMP)
                            Dim intAddns As Integer = SO(PS2_BOIL_ADDNS)
                            getAddns(intAddns)
                            'tbGrainTemp.Text = SO(PS2_GRAIN_TEMP) - not used in BT2
                            If SO(PS2_PROG_UNIT) = "0" Then
                                tb2Unit.Text = "Metric"
                            Else
                                tb2Unit.Text = "Imperial"
                            End If
                            blnLoadBTrecipe = False 'recipe data loaded

                        End If

                        'update recipe slot name with received data
                        If SO(PS2_PROG_NAME) <> "" Then
                            If IsNumeric(SO(PS2_PROG_NUM)) Then
                                Dim progNum As Integer = CInt(SO(PS2_PROG_NUM))
                                cboBTrecipeSlot.Items.RemoveAt(progNum)
                                cboBTrecipeSlot.Items.Insert(progNum, SO(PS2_PROG_NAME))
                                cboBTrecipeSlot.Text = SO(PS2_PROG_NAME)
                            Else
                                Exit Sub
                            End If
                        End If
                    Case "BOIL_TEMP"
                        DisplayInfo(DI_BOIL_TEMP) = SO(BOIL_TEMP)

                        If blnShowBoil Then
                            'show message on status screen
                            Dim strUnit As String = ""
                            If SO(BOIL_UNIT) = "0" Then
                                strUnit = "C"
                            Else
                                strUnit = "F"
                            End If
                            tsslMiscInfo.Text = "Boil Temp: " + SO(BOIL_TEMP) + Chr(176) + strUnit
                            tsslMiscInfo.Visible = True
                            tmrMessages.Interval = 5000
                            tmrMessages.Enabled = True    'show message for one timer tick
                            blnShowBoil = False
                        End If

                    Case "VOL_SET"
                        'indicates volume settings for specified vessel
                        Select Case SO(TUN_ID)
                            Case "0"
                                tbHLTmax.Enabled = True
                                tbHLTmax.TabIndex = SO(CAPACITY)
                                tbHLTmax.Enabled = False
                                My.Settings.asVolMaxHLT = SO(CAPACITY)
                                DisplayInfo(DI_HLT_CAPACITY) = SO(CAPACITY)
                                Settings.asHLTcap = SO(CAPACITY)
                                DisplayInfo(DI_HLT_DS) = SO(DEADSPACE)
                                Settings.asHLTds = SO(DEADSPACE)
                                If SO(TUN_UNIT) = "0" Then
                                    DisplayInfo(DI_HLT_UNIT) = "Litres"
                                    Settings.asHLTunit = "Litres"
                                Else
                                    DisplayInfo(DI_HLT_UNIT) = "Gallons"
                                    Settings.asHLTunit = "Gallons"
                                End If
                            Case "1"
                                tbMashMax.Enabled = True
                                tbMashMax.TabIndex = SO(CAPACITY)
                                tbMashMax.Enabled = False
                                My.Settings.asVolMaxMash = SO(CAPACITY)
                                DisplayInfo(DI_MASH_CAPACITY) = SO(CAPACITY)
                                Settings.asMASHcap = SO(CAPACITY)
                                DisplayInfo(DI_MASH_DS) = SO(DEADSPACE)
                                Settings.asMASHds = SO(DEADSPACE)
                                If SO(TUN_UNIT) = "0" Then
                                    DisplayInfo(DI_MASH_UNIT) = "Litres"
                                    Settings.asMASHunit = "Litres"
                                Else
                                    DisplayInfo(DI_MASH_UNIT) = "Gallons"
                                    Settings.asMASHunit = "Gallons"
                                End If
                            Case "2"
                                tbKetMax.Enabled = True
                                tbKetMax.TabIndex = SO(CAPACITY)
                                tbKetMax.Enabled = False
                                My.Settings.asVolMaxKet = SO(CAPACITY)
                                DisplayInfo(DI_KET_CAPACITY) = SO(CAPACITY)
                                Settings.asKETcap = SO(CAPACITY)
                                DisplayInfo(DI_KET_DS) = SO(DEADSPACE)
                                Settings.asKETds = SO(DEADSPACE)
                                If SO(TUN_UNIT) = "0" Then
                                    Settings.asKETunit = "Litres"
                                    DisplayInfo(DI_KET_UNIT) = "Litres"
                                Else
                                    Settings.asKETunit = "Gallons"
                                    DisplayInfo(DI_KET_UNIT) = "Gallons"
                                End If
                                If blnShowVsetDialog Then
                                    'show dialog
                                    If DlgBoxVset.ShowDialog = Windows.Forms.DialogResult.OK Then
                                        Dim strCapacity As String
                                        Dim strDeadSpace As String
                                        strCapacity = DlgBoxVset.tbHLTcap.Text
                                        strDeadSpace = DlgBoxVset.tbHLTds.Text
                                        AddToTXstack("SET_VSET+0+" + strCapacity + "+" + strDeadSpace)
                                        strCapacity = DlgBoxVset.tbMASHcap.Text
                                        strDeadSpace = DlgBoxVset.tbMASHds.Text
                                        AddToTXstack("SET_VSET+1+" + strCapacity + "+" + strDeadSpace)
                                        strCapacity = DlgBoxVset.tbKETcap.Text
                                        strDeadSpace = DlgBoxVset.tbKETds.Text
                                        AddToTXstack("SET_VSET+2+" + strCapacity + "+" + strDeadSpace)
                                    End If
                                    blnShowVsetDialog = False
                                End If
                        End Select
                End Select

            Case "CFG"
                'Configuration class

                Select Case SO(SER_MSG)
                    Case "CFGVER!"
                        DisplayInfo(DI_STEP_DESCR) = "Warning: BrewTroller EPROM configuration is invalid!"
                        If MsgBox("BrewTroller EPROM configuration is invalid! Do you wish to reset to default settings?", MsgBoxStyle.OkCancel, "Invalid EPROM") = MsgBoxResult.Ok Then
                            'send intialize eprom command
                            AddToTXstack("CFG+INIT_EEPROM-")
                        End If
                        'Case "BOIL_TEMP"
                        '    DisplayInfo(DI_BOIL_TEMP) = SO(BOIL_TEMP)

                        '    If blnShowBoil Then
                        '        'show message on status screen
                        '        tsslMiscInfo.Text = "Boil Temp: " + SO(BOIL_TEMP) + " " + SO(BOIL_UNIT)
                        '        tsslMiscInfo.Visible = True
                        '        tmrMessages.Interval = 5000
                        '        tmrMessages.Enabled = True    'show message for one timer tick
                        '        blnShowBoil = False
                        '    End If

                        'either have misc info panel for display only information OR
                        'display an extra indicator on the kettle temp gauge to show boil temp
                    Case "VOL_CALIB"
                        'not in use
                        'either have misc info panel for display only information AND/OR
                        'use for future setup wizard
                    Case "EVAP_RATE"
                        'not in use
                        'either have misc info panel for display only information AND/OR
                        'show as part of gauges

                        'Case "PROG_SET"
                        '    'saved recipe
                        '    Dim Prog_set(29) As String
                        '    For i = PS2_PROG_NUM To PS2_PROG_UNIT
                        '        Prog_set(i - 3) = SO(i)
                        '    Next

                        '    If blnLoadBTrecipe = True And intLoadBTrecipeNum = SO(PS2_PROG_NUM) Then
                        '        'we want to load these recipe values onto our session screen
                        '        tbRecipeName.Text = SO(PS2_PROG_NAME)
                        '        tbDoughIn.Text = SO(PS2_DI_TEMP)
                        '        tbDoughTime.Text = SO(PS2_DI_MINS)
                        '        tb2AcidTemp.Text = SO(PS2_ACID_TEMP)
                        '        tb2AcidTime.Text = SO(PS2_ACID_MINS)
                        '        tbProteinTemp.Text = SO(PS2_PROTEIN_TEMP)
                        '        tbProteinTime.Text = SO(PS2_PROTEIN_MINS)
                        '        tbSacchTemp.Text = SO(PS2_SACCH_TEMP)
                        '        tbSacchTime.Text = SO(PS2_SACCH_MINS)
                        '        tb2Sacch2Temp.Text = SO(PS2_SACCH2_TEMP)
                        '        tb2Sacch2Time.Text = SO(PS2_SACCH2_MINS)
                        '        tbMOtemp.Text = SO(PS2_MO_TEMP)
                        '        tbMOtime.Text = SO(PS2_MO_MINS)
                        '        tbSpargeTemp.Text = SO(PS2_SPARGE_TEMP)
                        '        'tbDelay.Text = SO(PS_DELAY_MINS) - not used in BT2
                        '        tbHLsetpoint.Text = SO(PS2_HLT_SET)
                        '        tbVol.Text = SO(PS2_BATCH_VOL)
                        '        tbGrainWeight.Text = SO(PS2_GRAIN_WGT)
                        '        tbBoilTotal.Text = SO(PS2_BOIL_MINS)
                        '        tbMashRatio.Text = SO(PS2_MASH_RATIO)
                        '        tbPitchTemp.Text = SO(PS2_PITCH_TEMP)
                        '        Dim intAddns As Integer = SO(PS2_BOIL_ADDNS)
                        '        getAddns(intAddns)
                        '        'tbGrainTemp.Text = SO(PS2_GRAIN_TEMP) - not used in BT2
                        '        If SO(PS2_PROG_UNIT) = "0" Then
                        '            tb2Unit.Text = "Metric"
                        '        Else
                        '            tb2Unit.Text = "Imperial"
                        '        End If
                        '        blnLoadBTrecipe = False 'recipe data loaded

                        '    End If

                        '    'update recipe slot name with received data
                        '    If SO(PS2_PROG_NAME) <> "" Then
                        '        cboBTrecipeSlot.Items.RemoveAt(SO(PS2_PROG_NUM))
                        '        cboBTrecipeSlot.Items.Insert(SO(PS2_PROG_NUM), SO(PS2_PROG_NAME))
                        '        cboBTrecipeSlot.Text = SO(PS2_PROG_NAME)
                        '    End If

                    Case Else

                End Select

            Case "CMD"
                'Command Class

                Select Case SO(SER_MSG)
                    Case "BAD_PARAM"
                        'Indicates a parameter to a command was rejected
                        tsslMiscInfo.Text = "BT BAD_PARAM " + SO(3) + " " + SO(4)
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case "MSG_OVERFLOW"
                        'Exceeded max number of input fields (20)
                        tsslMiscInfo.Text = "MSG_OVERFLOW"
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case "FIELD_OVERFLOW"
                        'Exceeded mas number of chars in command field (20)
                        tsslMiscInfo.Text = "FIELD_OVERFLOW"
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case "UNKNOWN_CMD"
                        'Invalid command
                        tsslMiscInfo.Text = "BT UNKNOWN_CMD " + SO(3) + " " + SO(4)
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case Else

                End Select


            Case "DATA"
                'Data class
                Select Case SO(SER_MSG)
                    Case "ALARM"
                        Call SerDatAlm(SO(ALM_STATUS))
                    Case "AUTOVLV"
                        If IsNumeric(SO(ALM_STATUS)) Then
                            Dim intValveStatus As Integer
                            intValveStatus = CInt(SO(ALM_STATUS))
                            Call SerAutoVlv2(intValveStatus)
                        End If

                    Case "HEATPWR"
                        Call SerHeatPwr(SO(TUN_ID), SO(DATA_VAL))

                        'Case "PGM"
                        '    Call serPgm(SO(PROG_ID))

                    Case "SETPOINT"
                        Call SerSetPoint(SO(TUN_ID), SO(DATA_VAL), SO(TEMP_UNIT))

                    Case "VLVBITS"
                        Call UpdateValvePanel(CSng(SO(VALVE_BITS)))

                    Case "STEAM"
                        '*** need to code this in

                    Case "STEPPRG"

                        Dim strProgDescr As String = " "

                        If SO(SP_FILL) <> "255" Then
                            strProgDescr = "#" & SO(SP_FILL) & ": Fill; "
                        End If
                        If SO(SP_DELAY) <> "255" Then
                            strProgDescr = "#" & SO(SP_DELAY) & ": Delay; "
                        End If
                        If SO(SP_PREHEAT) <> "255" Then
                            strProgDescr = "#" & SO(SP_PREHEAT) & ": Preheat; "
                        End If
                        If SO(SP_GRAIN_IN) <> "255" Then
                            strProgDescr = "#" & SO(SP_GRAIN_IN) & ": Grain in; "
                        End If
                        If SO(SP_REFILL) <> "255" Then
                            strProgDescr = "#" & SO(SP_REFILL) & ": Refill; "
                        End If
                        If SO(SP_DOUGH_IN) <> "255" Then
                            strProgDescr = "#" & SO(SP_DOUGH_IN) & ": Dough in; "
                        End If
                        If SO(SP_ACID) <> "255" Then
                            strProgDescr = "#" & SO(SP_ACID) & ": Acid rest; "
                        End If
                        If SO(SP_PROTEIN) <> "255" Then
                            strProgDescr = "#" & SO(SP_PROTEIN) & ": Protein rest; "
                        End If
                        If SO(SP_SACCH) <> "255" Then
                            strProgDescr = "#" & SO(SP_SACCH) & ": Sacch rest; "
                        End If
                        If SO(SP_SACCH2) <> "255" Then
                            strProgDescr = "#" & SO(SP_SACCH2) & ": Sacch2 rest; "
                        End If
                        If SO(SP_MASH_OUT) <> "255" Then
                            strProgDescr = "#" & SO(SP_MASH_OUT) & ": Mash out; "
                        End If
                        If SO(SP_MASH_HOLD) <> "255" Then
                            strProgDescr = "#" & SO(SP_MASH_HOLD) & ": Mash hold; "
                        End If
                        If SO(SP_SPARGE) <> "255" Then
                            strProgDescr = "#" & SO(SP_SPARGE) & ": Sparge; "
                        End If
                        If SO(SP_BOIL) <> "255" Then
                            strProgDescr = "#" & SO(SP_BOIL) & ": Boil; "
                        End If
                        If SO(SP_CHILL) <> "255" Then
                            strProgDescr = "#" & SO(SP_CHILL) & ": Chill; "
                        End If
                        If strProgDescr = " " Then strProgDescr = "[none]"
                        DisplayInfo(DI_RUNNING_PROGRAMS) = strProgDescr


                    Case "TEMP"
                        Call SerDatTemp(SO(TEMP_ID), SO(TEMP_VAL), SO(TEMP_UNIT))

                    Case "TIMER"
                        Call serTimer(SO(TIMER_ID2), SO(TIME_LEFT2), SO(TIMER_STATUS2))

                    Case "VOL"
                        Call serDatVol(SO(VOL_ID), SO(VOL_VAL), SO(VOL_UNIT))

                    Case "VLVPRF"
                        Call serDatVlvProf(SO(VLV_PROFILE_MASK))

                        updateDataDisplay() 'paginate serial data

                End Select

            Case "DEBUG"
                'Debug Class

                Select Case SO(SER_MSG)

                    Case "VOL_READ"
                        'detailed volume settings
                        If IsNumeric(SO(DATA_VAL)) Then

                            Select Case SO(TUN_ID)
                                Case "0"
                                    'HLT raw data
                                    DataInfo(DI_RAW_HLT) = SO(DATA_VAL)
                                    DisplayInfo(DI_RAW_HLT) = SO(DATA_VAL)
                                    If IsNumeric(SO(DATA_VAL)) Then
                                        If My.Settings.asBlnLogNow Then listHLTvolRaw.Add(Now.ToOADate, CDbl(SO(DATA_VAL)))
                                    End If
                                Case "1"
                                    'Mash raw data
                                    DataInfo(DI_RAW_MASH) = SO(DATA_VAL)
                                    DisplayInfo(DI_RAW_MASH) = SO(DATA_VAL)
                                    If IsNumeric(SO(DATA_VAL)) Then
                                        If My.Settings.asBlnLogNow Then listMashVolRaw.Add(Now.ToOADate, CDbl(SO(DATA_VAL)))
                                    End If
                                Case "2"
                                    'Mash raw data
                                    DataInfo(DI_RAW_KET) = SO(DATA_VAL)
                                    DisplayInfo(DI_RAW_KET) = SO(DATA_VAL)
                                    If IsNumeric(SO(DATA_VAL)) Then
                                        If My.Settings.asBlnLogNow Then listMashVolRaw.Add(Now.ToOADate, CDbl(SO(DATA_VAL)))
                                    End If
                                Case Else

                            End Select

                        End If
                        'NOTE: More detail is available under this command but not currently being processed.
                End Select

            Case "SYSTEM"
                'System Class

                Select Case SO(SER_MSG)
                    Case "VER"
                        'brewTroller firmware version and build information
                        'read version and build numbers
                        DisplayInfo(DI_VER) = SO(VER_NUM)
                        DisplayInfo(DI_BUILD) = SO(BUILD_NUM)
                        showBuildInfo()

                    Case "SOFT_RESET"
                        'indicates a soft reset is being performed
                        tsslMiscInfo.Text = "BT: Soft Reset"
                        tsslMiscInfo.Visible = True
                        tmrMessages.Interval = 5000
                        tmrMessages.Enabled = True    'show message for one timer tick

                    Case Else

                End Select
            Case Else
                '

        End Select

    End Sub

    Private Sub decodeFTdata(ByVal SO As Array)
        'process data received from FermTroller

        'at the moment we are doing nothing

    End Sub

    Private Sub updateDataDisplay()

        'handles pagination of received serial set and logging to file

        Static recordSetCount As Integer

        rtbBTcommsRx.Clear()    'clears current page of data
        rtbBTcommsRx.Text = rtbDisplay.Text 'copies full set of data from receive buffer to display area
        rtbDisplay.Clear()  'empties buffer in between sets

        'this is a fresh record set so increment counter if logging is active
        If cbLogData.Checked Then
            recordSetCount += 1
        Else
            recordSetCount = 0
        End If
        If recordSetCount >= 1 Then tsslLogMsg.Text = "Log on"

        'check if we log this set of records
        If recordSetCount >= My.Settings.as_nudLogInterval - 1 Then
            tsslLogMsg.Text = "Log NOW"
            recordSetCount = 0  'clear counter
            'and log current recordset
            Dim SessionFile As String = My.Settings.asLogFilePath + "\" + Format(Now, "yyMMdd") + ".btd"
            If Dir(SessionFile) = "" Then
                'Create new log file
                FileOpen(1, SessionFile, OpenMode.Append) ' create the text file named in the form text box
                FileClose(1)
            End If

            FileOpen(1, SessionFile, OpenMode.Append) ' open the text file named in the form text box
            Dim strNow As String = Now
            Dim msg As String = ""

            For i = 0 To rtbBTcommsRx.Lines.Length
                msg = strNow & vbTab & rtbBTcommsRx.Lines(i)
                PrintLine(1, msg)
            Next
            FileClose(1) ' close the file
        End If

    End Sub

    Private Sub DecodeSerialData()

        Dim counter As Integer
        'Create a string array and store the contents of the Lines property.
        Dim tempArray() As String
        tempArray = rtbDisplay.Lines
        'Loop through the array and send the contents of the array to debug window.
        For counter = tempArray.GetUpperBound(0) To tempArray.GetUpperBound(0)

            Try
                Dim SO = Split(tempArray(counter - 1), vbTab)
                If Settings.asBTversion = "BT1" Then
                    'BrewTroller ver 1.x data
                    decodeBT1data(SO)
                ElseIf Settings.asBTversion = "BT2" Then
                    'BrewTroller version 2.x data
                    decodeBT2data(SO)
                Else
                    'FermTroller received data
                    decodeFTdata(SO)
                End If

                If counter > 100 Then
                    rtbDisplay.Clear()
                End If

            Catch ex As Exception

            End Try

        Next

    End Sub

    Private Sub SerDatTemp(ByVal strTempProbe As String, ByVal strTempVal As String, ByVal strTempUnit As String)
        Dim strDisplay As String
        Dim valTemp As Double

        If IsNumeric(strTempVal) Then
            valTemp = CDbl(strTempVal)
        Else
            strTempVal = "-1.000"
        End If

        'format value
        If strTempVal = "-1.000" Or valTemp < -100 Then
            'probe is not connected, show "--.-"
            strDisplay = "--.-"
        Else
            If Settings.asBTversion = "BT2" Then
                strDisplay = (valTemp / 100).ToString("#0.0")
            Else
                strDisplay = valTemp.ToString("#0.0")
            End If
        End If

        'add temperature unit
        Dim strSuffix As String
        strSuffix = Chr(176)    'degree symbol
        If strTempUnit = "0" Then
            'celcius
            strSuffix = strSuffix + "C"
            strDegreeNotation = "C"   'degrees Celcius
            My.Settings.asBlnTempF = False
        Else
            'fahrenheit
            strSuffix = strSuffix + "F"
            strDegreeNotation = "F"   'degrees Farenheit
            My.Settings.asBlnTempF = True
        End If

        'save new value into data array (used for graphing)

        'refresh display variable

        Select Case strTempProbe
            Case "0"
                DataInfo(DI_HLT_TEMP) = strDisplay
                DisplayInfo(DI_HLT_TEMP) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listHLTTemp.Add(Now.ToOADate, valTemp)
                showBTconnected()   'we have valid data, ensure we show that BT is connected

            Case "1"
                DataInfo(DI_MASH_TEMP) = strDisplay
                DisplayInfo(DI_MASH_TEMP) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listMashTemp.Add(Now.ToOADate, valTemp)
                tsslBTtemp.Text = strDisplay
                tsslBTtemp.ToolTipText = "Mash temperature is: " & strDisplay & strSuffix
            Case "2"
                DataInfo(DI_KET_TEMP) = strDisplay
                DisplayInfo(DI_KET_TEMP) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listKetTemp.Add(Now.ToOADate, valTemp)
            Case "3"
                DataInfo(DI_TEMP_H2O_IN) = strDisplay
                DisplayInfo(DI_TEMP_H2O_IN) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listH2Oin.Add(Now.ToOADate, valTemp)
            Case "4"
                DataInfo(DI_TEMP_H2O_OUT) = strDisplay
                DisplayInfo(DI_TEMP_H2O_OUT) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listH2Oout.Add(Now.ToOADate, valTemp)
            Case "5"
                DataInfo(DI_TEMP_BEER) = strDisplay
                DisplayInfo(DI_TEMP_BEER) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listBeer.Add(Now.ToOADate, valTemp)
            Case "6"
                DataInfo(DI_TEMP_AUX1) = strDisplay
                DisplayInfo(DI_TEMP_AUX1) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listAux1.Add(Now.ToOADate, valTemp)
            Case "7"
                DataInfo(DI_TEMP_AUX2) = strDisplay
                DisplayInfo(DI_TEMP_AUX2) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listAux2.Add(Now.ToOADate, valTemp)
            Case "8"
                DataInfo(DI_TEMP_AUX3) = strDisplay
                DisplayInfo(DI_TEMP_AUX3) = strDisplay + strSuffix
                If My.Settings.asBlnLogNow Then listAux3.Add(Now.ToOADate, valTemp)
            Case Else

        End Select


    End Sub

    Private Sub serDatVol(ByVal strVolSender, ByVal strVolReturned, ByVal strVolUnit)
        Dim strDisplay As String
        Dim valVol As Double

        If IsNumeric(strVolReturned) Then
            valVol = CDbl(strVolReturned)
        Else
            strVolSender = "-1.000"
        End If

        'format value
        If strVolSender = "-1.000" Then
            'probe is not connected, show "--.-"
            strDisplay = "--.-"
        Else
            strDisplay = valVol.ToString("#0.0")
        End If

        If strVolUnit = "0" Then
            'litres
            strDisplay = strDisplay + " l"
        Else
            'Gallons
            strDisplay = strDisplay + " G"
        End If

        'save new value into data array (used for graphing)

        'refresh display variable

        Select Case strVolSender
            Case "0"
                DisplayInfo(DI_HLT_VOL) = strDisplay
                DataInfo(DI_HLT_VOL) = strVolReturned
                If My.Settings.asBlnLogNow Then listHLTvol.Add(Now.ToOADate, valVol)
            Case "1"
                DisplayInfo(DI_MASH_VOL) = strDisplay
                DataInfo(DI_MASH_VOL) = strVolReturned
                If My.Settings.asBlnLogNow Then listMashVol.Add(Now.ToOADate, valVol)
            Case "2"
                DisplayInfo(DI_KET_VOL) = strDisplay
                DataInfo(DI_KET_VOL) = strVolReturned
                If My.Settings.asBlnLogNow Then listKETvol.Add(Now.ToOADate, valVol)
            Case Else

        End Select

    End Sub

    Private Sub SerDatAlm(ByVal strAlarmStatus As String)

        If strAlarmStatus = "0" Then
            DisplayInfo(DI_ALARM_STATUS) = "OFF"
            tsslBTalarm.Text = "no alm"
            tsslBTalarm.ToolTipText = "No BrewTroller alarm"
        Else
            DisplayInfo(DI_ALARM_STATUS) = "ON"
            tsslBTalarm.Text = "ALM ON"
            tsslBTalarm.ToolTipText = "BrewTroller alarm is ON"
        End If

    End Sub

    Private Sub SerABstep(ByVal strStepNum As String)
        'Evaluates step number from serial data

        Dim strStepDesc As String
        Dim strStepSummary As String

        DisplayInfo(DI_ABSTEP_NUM) = strStepNum

        If intCurrBTstep <> CInt(strStepNum) Then
            intCurrBTstep = CInt(strStepNum)
            updateAutoValveStatus()
        End If

        Select Case strStepNum
            Case "1"
                strStepDesc = "Filling HLT and Mash tuns"
                strStepSummary = "Fill"
            Case "2"
                strStepDesc = "BrewTroller will resume after delay"
                strStepSummary = "Delay"
            Case "3"
                strStepDesc = "Preheating HLT and Mash liquor"
                strStepSummary = "Pre-heat"
            Case "4"
                strStepDesc = "Adding grains to mash tun"
                strStepSummary = "Add Grains"
            Case "5"
                strStepDesc = "Doughing in"
                strStepSummary = "Dough-in"
            Case "6"
                strStepDesc = "Protein rest"
                strStepSummary = "Protein"
            Case "7"
                strStepDesc = "Saccharification rest"
                strStepSummary = "Sacch"
            Case "8"
                strStepDesc = "Mash out"
                strStepSummary = "MashOut"
            Case "9"
                strStepDesc = "End of mash"
                strStepSummary = "MashEnd"
            Case "10"
                strStepDesc = "Sparge"
                strStepSummary = "Sparge"
            Case "11"
                strStepDesc = "Boil"
                strStepSummary = "Boil"
            Case "12"
                strStepDesc = "Chill"
                strStepSummary = "Chill"
            Case Else
                strStepDesc = ""
                strStepSummary = "[no step]"
        End Select

        DisplayInfo(DI_STEP_DESCR) = strStepDesc
        tsslBTstep.Text = strStepSummary
        tsslBTstep.ToolTipText = strStepDesc

    End Sub

    Private Sub SerAutoVlv(ByVal strValve_Status As String)

        Dim strStepDesc As String

        Select Case strValve_Status
            Case "0"
                strStepDesc = "OFF"
            Case "1"
                strStepDesc = "Fill"
            Case "2"
                strStepDesc = "Mash"
            Case "3"
                strStepDesc = "Sparge"
            Case "4"
                strStepDesc = "Chill"
        End Select

        DisplayInfo(DI_AUTO_VLV_DESCR) = strStepDesc
        'lblAutoValve.Text = strStepDesc
        'tsslBTvalveProfile.Text = "VLV-" & strStepDesc
        'tsslBTvalveProfile.ToolTipText = "Current valve profile is:- " & strStepDesc

    End Sub

    Private Sub SerAutoVlv2(ByVal intValve_Status As Integer)

        Dim strStepDesc As String

        If intValve_Status = 0 Then
            strStepDesc = "[None]"
        Else
            If intValve_Status >= 32 Then
                strStepDesc = "Chill;"
                intValve_Status -= 32
            End If
            If intValve_Status >= 16 Then
                strStepDesc &= "Fly Sparge;"
                intValve_Status -= 16
            End If
            If intValve_Status >= 8 Then
                strStepDesc &= "Sparge Out;"
                intValve_Status -= 8
            End If
            If intValve_Status >= 4 Then
                strStepDesc &= "Sparge In;"
                intValve_Status -= 4
            End If
            If intValve_Status >= 2 Then
                strStepDesc &= "Mash;"
                intValve_Status -= 2
            End If
            If intValve_Status >= 1 Then
                strStepDesc &= "Fill;"
                intValve_Status -= 1
            End If
        End If

        DisplayInfo(DI_AUTO_VLV_DESCR) = strStepDesc
        'lblAutoValve.Text = strStepDesc

    End Sub
    Public Sub SerHeatPwr(ByVal strTun As String, ByVal strVal As String)

        Dim strShow As String
        Dim strColor As Color

        Select Case strVal
            Case "0"
                strShow = "OFF"
            Case "100"
                strShow = "ON"
            Case Else
                If IsNumeric(strVal) Then
                    strShow = strVal + "%"
                Else
                    strShow = "--"
                End If
        End Select

        Select Case strTun
            Case "0"
                'HLT
                DisplayInfo(DI_HLT_HEAT) = strShow
            Case "1"
                DisplayInfo(DI_MASH_HEAT) = strShow
            Case "2"
                DisplayInfo(DI_KET_HEAT) = strShow
            Case "3"
                DisplayInfo(DI_STEAM_HEAT) = strShow

        End Select
    End Sub

    Private Sub SerSetPoint(ByVal strTun As String, ByVal strVal As String, ByVal strUnit As String)

        Dim strDisplay As String
        Dim valSetPoint As Double

        If IsNumeric(strVal) Then
            valSetPoint = CDbl(strVal)
        Else
            strVal = "-1.000"
        End If

        'format value
        If strVal = "-1.000" Then
            'probe is not connected, show "--.-"
            strDisplay = "--.-"
        Else
            strDisplay = valSetPoint.ToString("#0.0")
        End If

        'add temperature unit
        Dim strSuffix As String
        strSuffix = Chr(176)    'degree symbol
        If strUnit = "0" Then
            'celcius
            strSuffix = strSuffix + "C"
            strDegreeNotation = "C"   'degrees Celcius
        Else
            'fahrenheit
            strSuffix = strSuffix + "F"
            strDegreeNotation = "F"   'degrees Farenheit
        End If

        'save new value into data array (used for graphing)

        'refresh display variable

        Select Case strTun
            Case "0"
                DisplayInfo(DI_HLT_SET) = strDisplay + strSuffix
                DataInfo(DI_HLT_SET) = strDisplay
                If My.Settings.asBlnLogNow Then listHLTsp.Add(Now.ToOADate, valSetPoint)
            Case "1"
                DisplayInfo(DI_MASH_SET) = strDisplay + strSuffix
                DataInfo(DI_MASH_SET) = strDisplay
                If My.Settings.asBlnLogNow Then listMashSP.Add(Now.ToOADate, valSetPoint)
            Case "2"
                DisplayInfo(DI_KET_SET) = strDisplay + strSuffix
                DataInfo(DI_KET_SET) = strDisplay
                If My.Settings.asBlnLogNow Then listKetPwr.Add(Now.ToOADate, valSetPoint)
        End Select


    End Sub

    Private Sub serPgm(ByVal strID As String)

        Dim strMsgSummary As String
        Dim strMsgToolTip As String

        If strID = "0" Then
            DisplayInfo(DI_PGM_ID) = "none"
            strMsgSummary = "[no Prog]"
            strMsgToolTip = "No BrewTroller program running"
            tsslBTstep.Text = "[no step]"
            DisplayInfo(DI_STEP_DESCR) = "[none]"
            tsslBTvalveProfile.Text = "[no valve]"
            tsslBTalarm.Text = "[no ALM]"
            btnStepNext.Enabled = False
            btnStepPrev.Enabled = False
        ElseIf strID = "1" Then
            DisplayInfo(DI_PGM_ID) = "Auto Brew"
            strMsgSummary = "AutoBrew"
            strMsgToolTip = "BrewTroller is running Auto Brew"
            btnStepNext.Enabled = True
            btnStepPrev.Enabled = True
        ElseIf strID = "2" Then
            DisplayInfo(DI_PGM_ID) = "Brew Monitor"
            strMsgSummary = "BrewMon"
            strMsgToolTip = "BrewTroller is running Brew Monitor"
            btnStepNext.Enabled = False
            btnStepPrev.Enabled = False
        End If

        tsslBTprogram.ToolTipText = strMsgToolTip
        tsslBTprogram.Text = strMsgSummary

    End Sub

    Private Sub serTimer(ByVal strTimerID As String, ByVal strTimeLeft As String, ByVal strTimerStatus As String)

        Dim strTimeResult As String
        Dim strBTtimerStatus As String
        Dim lngTimeLeft As Long
        Dim intHours As Integer
        Dim intMins As Integer
        Dim intSecs As Integer

        If IsNumeric(strTimeLeft) Then
            lngTimeLeft = CLng(strTimeLeft)
            DisplayInfo(DI_TIME_MILLIS) = lngTimeLeft

            'convert time left to seconds (/1000)
            lngTimeLeft = lngTimeLeft / 1000

            If strTimerStatus = "0" And lngTimeLeft > 0 Then
                'Timer is stopped but there is time left on the clock
                strBTtimerStatus = "Paused"
                'make run / pause button read accordingly
                btnTimRunPause.Text = "Run"
                btnTimRunPause.BackColor = Color.OrangeRed

            ElseIf strTimerStatus = "0" And lngTimeLeft = 0 Then
                strBTtimerStatus = "Stopped"
            ElseIf strTimerStatus = "1" Then
                strBTtimerStatus = "Running"
                'make run / pause button read accordingly
                btnTimRunPause.Text = "Pause"
                btnTimRunPause.BackColor = Color.GreenYellow
            End If

            'convert seconds into hours, minutes and seconds

            intHours = Int((lngTimeLeft / 3600))
            lngTimeLeft = lngTimeLeft - (intHours * 3600)
            intMins = Int((lngTimeLeft / 60))
            lngTimeLeft = lngTimeLeft - (intMins * 60)
            intSecs = lngTimeLeft

            If intHours > 0 Then
                strTimeResult = intHours.ToString("#0") + ":" + intMins.ToString("00") + ":" + intSecs.ToString("00")
            Else
                strTimeResult = intMins.ToString("#0") + ":" + intSecs.ToString("00")
            End If
        Else
            strTimeResult = "--:--"
        End If

        If strTimerID = "0" Then
            'this is our mash timer
            DisplayInfo(DI_TIME_VAL) = strTimeResult
            DisplayInfo(DI_TIME_STATUS) = strBTtimerStatus
            tsslBTmashTimer.Text = "Mash: " & strTimeResult
            tsslBTmashTimer.ToolTipText = "Mash timer is " & strBTtimerStatus
        ElseIf strTimerID = "1" Then
            'this is our boil timer
            DisplayInfo(DI_TIME_VAL2) = strTimeResult
            DisplayInfo(DI_TIME_STATUS2) = strBTtimerStatus
            tsslBTboilTimer.Text = "Boil: " & strTimeResult
            tsslBTboilTimer.ToolTipText = "Boil timer is " & strBTtimerStatus
        ElseIf strTimerID = "BT1" Then
            'this is a BT1.x system timer
            DisplayInfo(DI_TIME_VAL) = strTimeResult
            DisplayInfo(DI_TIME_STATUS) = strBTtimerStatus
            tsslBTmashTimer.Text = strTimeResult
            tsslBTmashTimer.ToolTipText = "BrewTroller timer is " & strBTtimerStatus
        End If

    End Sub
    Private Sub serDatVlvProf(ByVal strProfileMask As String)

        Dim strValveProfile As String = Nothing
        Dim strValveSummary As String = Nothing

        If IsNumeric(strProfileMask) Then
            'decode bits
            strValveSummary = "VLV:"
            Dim intProfileMask As Int16 = CInt(strProfileMask)
            If ExamineBit(intProfileMask, 1) Then
                intPrimActiveValveProfile = 0
                strValveProfile = "Fill HLT; "
                strValveSummary = "FILLHLT; "
            End If
            If ExamineBit(intProfileMask, 2) Then
                intPrimActiveValveProfile = 1
                strValveProfile &= "Fill Mash; "
                strValveSummary &= "FILLMASH; "
            End If
            If ExamineBit(intProfileMask, 3) Then
                intPrimActiveValveProfile = 2
                strValveProfile &= "Add Grain ;"
                strValveSummary &= "ADDGRAIN; "
            End If
            If ExamineBit(intProfileMask, 4) Then
                intPrimActiveValveProfile = 3
                strValveProfile &= "Mash heat; "
                strValveSummary &= "MASHHEAT; "
            End If
            If ExamineBit(intProfileMask, 5) Then
                intPrimActiveValveProfile = 4
                strValveProfile &= "Mash idle; "
                strValveSummary &= "MASHIDLE; "
            End If
            If ExamineBit(intProfileMask, 6) Then
                intPrimActiveValveProfile = 5
                strValveProfile &= "Sparge in; "
                strValveSummary &= "SPARGEIN; "
            End If
            If ExamineBit(intProfileMask, 7) Then
                intPrimActiveValveProfile = 6
                strValveProfile &= "Sparge out; "
                strValveSummary &= "SPARGEOUT; "
            End If
            If ExamineBit(intProfileMask, 8) Then
                intPrimActiveValveProfile = 7
                strValveProfile &= "Boil addition ;"
                strValveSummary &= "BOILADDN; "
            End If
            If ExamineBit(intProfileMask, 9) Then
                intPrimActiveValveProfile = 8
                strValveProfile &= "Kettle lid; "
                strValveSummary &= "KETTLELID; "
            End If
            If ExamineBit(intProfileMask, 10) Then
                intPrimActiveValveProfile = 9
                strValveProfile &= "Chill Water; "
                strValveSummary &= "CHILLH20; "
            End If
            If ExamineBit(intProfileMask, 11) Then
                intPrimActiveValveProfile = 10
                strValveProfile &= "Chill Beer; "
                strValveSummary &= "CHILLBEER; "
                intPrimActiveValveProfile = 11
                strValveProfile &= "Boil Recirc; "
                strValveSummary &= "BOILRECIRC; "
            End If
            If ExamineBit(intProfileMask, 12) Then
                intPrimActiveValveProfile = 11
                strValveProfile &= "Drain; "
                strValveSummary &= "DRAIN;"
            End If

        Else
            Exit Sub
        End If

        If strValveProfile = "" Then
            strValveProfile = "[none]"
            strValveSummary &= "OFF"
        End If

        DisplayInfo(DI_VLV_PROF) = strValveProfile
        tsslBTvalveProfile.Text = strValveSummary

    End Sub

#End Region

#Region "Comms to BrewTroller"

    Private Sub sendBTstring(ByVal strCommandLine)
        If cbSerialConnect.Checked = False Then
            'the serial port is not yet open, ignore serial request and show error on status bar
            tsslMiscInfo.Text = "BT Com n/a: " + strCommandLine
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 5000
            tmrMessages.Enabled = True    'show message for one timer tick
        Else
            comm.WriteData(strCommandLine)  'send the command
        End If
    End Sub

    Private Function getFromTXstack() As String
        'is triggered by tmrSendToBT
        'checks to see if there is a message in the stack
        'returns either a valid message to sent to the BT or the string value "False" if there is no message to send

        If strSerialMsg(0) <> Nothing Then
            'return a valid command
            getFromTXstack = serTranslate(strSerialMsg(0))
            'shuffle stack
            For i = 1 To 100
                strSerialMsg(i - 1) = strSerialMsg(i)
            Next
            'clear bottom stack entry
            strSerialMsg(100) = Nothing
        Else
            'return a "False" message
            getFromTXstack = "False"
        End If

    End Function


    Function serTranslate(ByVal strCmd As String) As String

        'translates + as vbTAB and - as vbCr for BT command string
        strCmd = strCmd.Replace("+", vbTab)
        strCmd = strCmd.Replace("-", vbCr)

        'return new command string
        serTranslate = strCmd

    End Function

#End Region

#Region "Timers"

    Private Sub tmrRefresh_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrRefresh.Tick

        Call manageXML()   'creates the xml file for the display panel
        Call UpdateControlPanel()   'updates the control panel
        'wbPanel.Refresh()   'refreshes the web panel showing local data

        If cbGoLive.Checked Then UpdateGraph()
        wbPanel.AllowNavigation = False
        wbLiveData.AllowNavigation = False

    End Sub

#End Region

#Region "Menus"

    Private Sub AutoBrewToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoBrewToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+1-RESET+SURE-")
    End Sub

    Private Sub BrewMonitorToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BrewMonitorToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+2-RESET+SURE-")
    End Sub

    Private Sub STOPToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles STOPToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+0-RESET+SURE-")
    End Sub

    Private Sub ConnectToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ConnectToolStripMenuItem.Click
        If Not String.IsNullOrEmpty(cboPort.Text) Then
            cbSerialConnect.Checked = Not cbSerialConnect.Checked
        Else
            MsgBox("Please select a com port from the drop down list on the status bar.", MsgBoxStyle.Information)
        End If
    End Sub

    Private Sub FILLToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FILLToolStripMenuItem2.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+1-RESET+SURE-")
    End Sub

    Private Sub DelayStartToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DelayStartToolStripMenuItem.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+2-RESET+SURE-")
    End Sub

    Private Sub PreheatToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PreheatToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+3-RESET+SURE-")
    End Sub

    Private Sub AddGrainToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddGrainToolStripMenuItem2.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+4-RESET+SURE-")
    End Sub

    Private Sub RefillToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RefillToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+5-RESET+SURE-")
    End Sub

    Private Sub DoughInToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DoughInToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+6-RESET+SURE-")
    End Sub

    Private Sub ProteinRestToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ProteinRestToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+7-RESET+SURE-")
    End Sub

    Private Sub SacchRestToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SacchRestToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+8-RESET+SURE-")
    End Sub

    Private Sub MashOutToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MashOutToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+9-RESET+SURE-")
    End Sub

    Private Sub EndOfMashToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles EndOfMashToolStripMenuItem.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+10-RESET+SURE-")
    End Sub

    Private Sub SpargeToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SpargeToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+11-RESET+SURE-")
    End Sub

    Private Sub BoilToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BoilToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+12-RESET+SURE-")
    End Sub

    Private Sub ChillToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ChillToolStripMenuItem1.Click
        AddToTXstack("SET_PLR+1-SET_ABSTEP+13-RESET+SURE-")
    End Sub

    Private Sub ENDToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ENDToolStripMenuItem.Click
        AddToTXstack("SET_PLR+0-RESET+SURE-")
    End Sub

    Private Sub FillHLTToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FillHLTToolStripMenuItem.Click, FillMashToolStripMenuItem.Click

        'ensure that only fill profiles, kettle lid or boil addition profiles can be checked

        'FillHLTToolStripMenuItem.Checked = False
        'FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If FillHLTToolStripMenuItem.Checked Then intValveProfile += 1
        If FillMashToolStripMenuItem.Checked Then intValveProfile += 2
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256

        AddToTXstack("SET_PLR+1-SET_ABSTEP+1-RESET+SURE-ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub HLTToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HLTToolStripMenuItem1.Click

        Dim strSet As String

        strSet = InputBox("Enter setpoint:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_SETPOINT+0+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If

    End Sub

    Private Sub MashToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MashToolStripMenuItem1.Click

        Dim strSet As String

        strSet = InputBox("Enter setpoint:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_SETPOINT+1+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If


    End Sub

    Private Sub KettleToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles KettleToolStripMenuItem1.Click

        Dim strSet As String

        strSet = InputBox("Enter setpoint:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_SETPOINT+2+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If


    End Sub

    Private Sub HLTClearToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HLTClearToolStripMenuItem.Click
        AddToTXstack("SET_SETPOINT+0+0-")
    End Sub

    Private Sub MashClearToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MashClearToolStripMenuItem.Click
        AddToTXstack("SET_SETPOINT+1+0-")
    End Sub

    Private Sub KettleClearToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles KettleClearToolStripMenuItem.Click
        AddToTXstack("SET_SETPOINT+2+0-")
    End Sub

    Private Sub AddGrainToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddGrainToolStripMenuItem.Click

        'ensure that only add grain, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        'AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If AddGrainToolStripMenuItem.Checked Then intValveProfile += 4
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256

        AddToTXstack("SET_PLR+1-SET_ABSTEP+4-RESET+SURE-ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub MashHeatToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MashHeatToolStripMenuItem.Click

        'ensure that only mash heat, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        'MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If MashHeatToolStripMenuItem.Checked Then intValveProfile += 8
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256

        AddToTXstack("SET_PLR+1-SET_ABSTEP+7-RESET+SURE-ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub MashIdleToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MashIdleToolStripMenuItem.Click

        'ensure that only mash idle, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        'MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If MashIdleToolStripMenuItem.Checked Then intValveProfile += 16
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256

        AddToTXstack("SET_PLR+1-SET_ABSTEP+7-RESET+SURE-ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub SpargeInToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SpargeInToolStripMenuItem.Click, SpargeOutToolStripMenuItem.Click

        'ensure that only sparge, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        'SpargeInToolStripMenuItem.Checked = False
        'SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If SpargeInToolStripMenuItem.Checked Then intValveProfile += 32
        If SpargeOutToolStripMenuItem.Checked Then intValveProfile += 64
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256

        AddToTXstack("SET_PLR+1-SET_ABSTEP+11-RESET+SURE-ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub ChillerH2OToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ChillerH2OToolStripMenuItem.Click, ChillerBeerToolStripMenuItem.Click

        'ensure that only chiller, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        'ChillerBeerToolStripMenuItem.Checked = False
        'ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256
        If ChillerH2OToolStripMenuItem.Checked Then intValveProfile += 512
        If ChillerBeerToolStripMenuItem.Checked Then intValveProfile += 1024

        AddToTXstack("SET_PLR+1-SET_ABSTEP+11-RESET+SURE-ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub BoilAdditionToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BoilAdditionToolStripMenuItem.Click, KettleLidToolStripMenuItem.Click

        '
        'FillHLTToolStripMenuItem.Checked = False
        'FillMashToolStripMenuItem.Checked = False
        'AddGrainToolStripMenuItem.Checked = False
        'MashHeatToolStripMenuItem.Checked = False
        'MashIdleToolStripMenuItem.Checked = False
        'SpargeInToolStripMenuItem.Checked = False
        'SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        'BoilRecircToolStripMenuItem.Checked = False
        'ChillerBeerToolStripMenuItem.Checked = False
        'ChillerH2OToolStripMenuItem.Checked = False
        'DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If FillHLTToolStripMenuItem.Checked Then intValveProfile += 1
        If FillMashToolStripMenuItem.Checked Then intValveProfile += 2
        If AddGrainToolStripMenuItem.Checked Then intValveProfile += 4
        If MashHeatToolStripMenuItem.Checked Then intValveProfile += 8
        If MashIdleToolStripMenuItem.Checked Then intValveProfile += 16
        If SpargeInToolStripMenuItem.Checked Then intValveProfile += 32
        If SpargeOutToolStripMenuItem.Checked Then intValveProfile += 64
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256
        If ChillerH2OToolStripMenuItem.Checked Then intValveProfile += 512
        If ChillerBeerToolStripMenuItem.Checked Then intValveProfile += 1024
        If BoilRecircToolStripMenuItem.Checked Then intValveProfile += 2048
        If DrainToolStripMenuItem.Checked Then intValveProfile += 4096

        AddToTXstack("ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub DrainToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DrainToolStripMenuItem.Click

        'ensure that only drain, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        'DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256
        If DrainToolStripMenuItem.Checked Then intValveProfile += 4096

        AddToTXstack("ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub


    Private Sub BoilRecircToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BoilRecircToolStripMenuItem.Click

        'ensure that only boil recirc, kettle lid or boil addition profiles can be checked

        FillHLTToolStripMenuItem.Checked = False
        FillMashToolStripMenuItem.Checked = False
        AddGrainToolStripMenuItem.Checked = False
        MashHeatToolStripMenuItem.Checked = False
        MashIdleToolStripMenuItem.Checked = False
        SpargeInToolStripMenuItem.Checked = False
        SpargeOutToolStripMenuItem.Checked = False
        'BoilAdditionToolStripMenuItem.Checked = False
        'KettleLidToolStripMenuItem.Checked = False
        'BoilRecircToolStripMenuItem.Checked = False
        ChillerBeerToolStripMenuItem.Checked = False
        ChillerH2OToolStripMenuItem.Checked = False
        DrainToolStripMenuItem.Checked = False

        'evaluate valve profile
        Dim intValveProfile As Integer = 0
        If BoilAdditionToolStripMenuItem.Checked Then intValveProfile += 128
        If KettleLidToolStripMenuItem.Checked Then intValveProfile += 256
        If BoilRecircToolStripMenuItem.Checked Then intValveProfile += 2048

        AddToTXstack("ACT_VLVPRF+" + Str(intValveProfile) + "-")

    End Sub

    Private Sub SETvalveprofileOFFToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SETvalveprofileOFFToolStripMenuItem.Click

        AddToTXstack("ACT_VLVPRF+0-")

    End Sub

    Private Sub AutoFILLToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoFILLToolStripMenuItem1.Click
        AddToTXstack("SET_AUTOVLV+1-")
    End Sub

    Private Sub AutoMashToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoMashToolStripMenuItem1.Click
        AddToTXstack("SET_AUTOVLV+2-")
    End Sub

    Private Sub AutoSpargeToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoSpargeToolStripMenuItem1.Click
        AddToTXstack("SET_AUTOVLV+3-")
    End Sub

    Private Sub AutoChillToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoChillToolStripMenuItem1.Click
        AddToTXstack("SET_AUTOVLV+4-")
    End Sub

    Private Sub OFFToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OFFToolStripMenuItem2.Click
        AddToTXstack("SET_AUTOVLV+0-")
    End Sub

    Private Sub ValueToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ValueToolStripMenuItem.Click

        Dim strVal As String = InputBox("Enter timer value :", , "mm:ss")

        'change entered separator to ':'
        strVal = strVal.Replace(".", ":")
        strVal = strVal.Replace(" ", ":")

        Dim hhmm As String() = Nothing
        Dim hrVal As String = Nothing
        Dim minVal As String = Nothing
        Dim secVal As String = Nothing
        Dim millis As Double = 0

        hhmm = strVal.Split(":")

        Dim s As String
        Dim item As Integer = 0

        For Each s In hhmm
            If Not IsNumeric(s) Then
                MsgBox("Please enter a valid time in format " + vbCrLf + "'mm:ss' or 'hh:mm:ss' OR " + vbCrLf + "'mm.ss' or 'hh.mm.ss' OR" + vbCrLf + "'mm ss' or 'hh mm ss'", MsgBoxStyle.Exclamation)
                Exit Sub
            End If
            If item = 0 Then
                hrVal = s
            ElseIf item = 1 Then
                minVal = s
            ElseIf item = 2 Then
                secVal = s
            End If

            item += 1

        Next s

        If secVal = Nothing Then
            'we only had two items, shift them to represent mins and secs rather than hrs and mins
            secVal = minVal
            minVal = hrVal
            hrVal = Nothing
        End If
        'work out millis
        millis = CInt(hrVal) * 3600000 + CInt(minVal) * 60000 + CInt(secVal) * 1000

        AddToTXstack("SET_TIMERVALUE+" + CStr(millis) + "-")

    End Sub

    Private Sub RUNToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RUNToolStripMenuItem.Click
        AddToTXstack("SET_TIMERSTATUS+1-")
    End Sub

    Private Sub PAUSEToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PAUSEToolStripMenuItem.Click
        AddToTXstack("SET_TIMERSTATUS+0-")
    End Sub

    Private Sub STOPToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles STOPToolStripMenuItem2.Click
        AddToTXstack("SET_TIMERVALUE+0-SET_TIMERSTATUS+0-")
    End Sub

    Private Sub CLEARAlarmToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CLEARAlarmToolStripMenuItem.Click
        AddToTXstack("SET_ALARM+0-")
    End Sub

#End Region

#Region "other"

    Private Sub cbFTPupload_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbFTPupload.CheckedChanged
        If cbFTPupload.Checked = True Then
            tmrFTPandLog.Enabled = True
        Else
            tsslMiscInfo.Text = "Web streaming disconnected"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 10000
            tmrMessages.Enabled = True
        End If
    End Sub

    Private Sub btnLoadGraph_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadGraph.Click

        loadGraphFile()

    End Sub

    Private Sub btnXML_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim Capital As String = "Washington"
        Dim Cities As String = "NewYork"
        Dim rank As Integer = 1
        Dim settings As New XmlWriterSettings()
        settings.Indent = True
        settings.NewLineOnAttributes = True

        'Dim filename As String = Path.Combine(, "xmlfile.xml")
        Using writer As XmlWriter = XmlWriter.Create(Application.StartupPath() + "\xmlfile.xml", settings)
            writer.WriteStartDocument()
            writer.WriteStartElement("countries")
            writer.WriteStartElement("UnitedStates")
            writer.WriteStartAttribute("capital")
            writer.WriteValue(Capital)
            writer.WriteEndAttribute()
            writer.WriteStartAttribute("Cities")
            writer.WriteValue(Cities)
            writer.WriteEndAttribute()
            writer.WriteStartAttribute("rank")
            writer.WriteValue(rank)
            writer.WriteEndAttribute()
            writer.WriteEndElement()
            writer.WriteEndDocument()
            writer.Flush()
        End Using
    End Sub

    Private Sub btnReadXML_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        ' Create an isntance of XmlTextReader and call Read method to read the(file)
        Dim textReader As XmlTextReader = New XmlTextReader(Application.StartupPath() + "\graph.xml")
        textReader.Read()
        ' If the node has value
        If textReader.HasValue Then
            ' Move to fist element
            textReader.MoveToElement()
            Console.WriteLine("XmlTextReader Properties Test")
            Console.WriteLine("===================")
            ' Read this element's properties and display them on console
            Console.WriteLine("Name:" + textReader.Name)
            Console.WriteLine("Base URI:" + textReader.BaseURI)
            Console.WriteLine("Local Name:" + textReader.LocalName)
            Console.WriteLine("Attribute Count:" + textReader.AttributeCount.ToString())
            Console.WriteLine("Depth:" + textReader.Depth.ToString())
            Console.WriteLine("Line Number:" + textReader.LineNumber.ToString())
            Console.WriteLine("Node Type:" + textReader.NodeType.ToString())
            Console.WriteLine("Attribute Count:" + textReader.Value.ToString())
        End If
    End Sub

    Private Sub rbTypeTemp_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        'If rbTypeTemp.Checked Then
        '    gbTemps.Visible = True
        '    gbVols.Visible = False
        'Else
        '    gbTemps.Visible = False
        '    gbVols.Visible = True
        'End If
    End Sub

    Private Sub btnRefreshGraph_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRefreshGraph.Click
        CreateNewGraph()
    End Sub

    Private Sub btnLoadRecipe_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadRecipe.Click

        Dim bExOccured As Boolean

        Dim strDataFile As String

        'open file dialog
        Dim MyFileOpen As New System.Windows.Forms.OpenFileDialog
        MyFileOpen.InitialDirectory = My.Settings.asXMLpath
        Dim strFileExt As String    'checks extension for version compatability between Promash Text and BeerSmith xml
        Dim retVal As DialogResult

        Try
            ' does not add an extension to a file name if the user omits the extension
            MyFileOpen.AddExtension = True

            'dialog box does not allow multiple files to be selected
            MyFileOpen.Multiselect = False

            MyFileOpen.Filter = "BeerXML files (*.xml)|*.xml"

            retVal = MyFileOpen.ShowDialog()
            If retVal = Windows.Forms.DialogResult.OK Then

                If MyFileOpen.CheckFileExists = True And MyFileOpen.CheckPathExists = True Then

                    My.Settings.asStrRecipeFile = MyFileOpen.FileName    'save current filename
                    My.Settings.asXMLpath = System.IO.Path.GetDirectoryName(MyFileOpen.FileName)
                    SaveMySettings()
                End If

            End If
        Catch ex1 As AccessViolationException
            MsgBox(ex1.StackTrace.ToString)
            bExOccured = True
        Catch ex As Exception
            MsgBox(ex.StackTrace.ToString)
            bExOccured = True
        Finally
            If bExOccured = True Then
                MsgBox("Program executed with some errors!!!")
            End If
        End Try

        If bExOccured Then
            MsgBox("Problem loading recipe file, cannot process data.")
            'lblGraphStatus.Text = "Problem loading data file"
            Exit Sub
        End If

        'check file extension and decode for ProMash or BeerSmith

        strDataFile = My.Settings.asStrRecipeFile
        Dim strDataFileNameOnly As String = IO.Path.GetFileNameWithoutExtension(strDataFile)
        strFileExt = IO.Path.GetExtension(strDataFile)
        Dim blnProMash As Boolean = True
        If strFileExt = ".rec" Then
            'decode the ProMash data using converter.exe
            If strDataFile.Length > 4 Then
                'we want just the directory so that we can convert all promash recipes as a bulk lot
                Dim strPath As String = IO.Path.GetDirectoryName(strDataFile)
                Dim strCmdLine As String = Application.StartupPath() + "\converter.exe " & strPath & " /p"
                'System.Diagnostics.Process.Start(strCmdLine)
            End If
        ElseIf strFileExt = ".xml" Then
            'load the xml file to rtbFile
            strXMLdata = ""
            oRead = oFile.OpenText(My.Settings.asStrRecipeFile)
            While Not oRead.EndOfStream
                'rtbFile.Text = oRead.ReadToEnd
                strXMLdata &= oRead.ReadLine
            End While

            'decode the beersmith xml data
            Call GetBeerSmithList()
        Else
            'MsgBox("Sorry but this feature is not yet functional")
        End If

    End Sub


    Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Call GetBTrecipeNames()

    End Sub

    Private Sub btnSendRecipeToBT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSendRecipeToBT.Click

        'validate before allow data to be sent
        validateRecipe()

        'saves recipe data to BT using selected recipe slot from session combo box

        'check to see if we need an overwrite warning message
        If Settings.asBTversion = "BT1" Then
            If cbAskSlotOverWrite.Checked Then
                'check to see if this slot has been used before
                If cboBTrecipeSlot.Text.Substring(0, 4) <> "Slot" Then
                    'this looks like a used recipe slot, show warning message
                    If MsgBox("Do you wish to overwrite this recipe slot?", MsgBoxStyle.OkCancel, "Overwrite recipe") = MsgBoxResult.Cancel Then
                        Exit Sub
                    End If
                End If
            End If
        End If

        'create recipe data string to send to BT

        Dim strTxData As String

        If Settings.asBTversion = "BT1" Then
            'if slot 0 is selected we will send as autobrew set
            If cboBTrecipeSlot.SelectedIndex = 0 Then
                strTxData = "SET_ABSET" + vbTab
            Else
                'regular BT1 program slot
                strTxData = "SET_PROG" + vbTab      'command [0]
                strTxData = strTxData + Str(cboBTrecipeSlot.SelectedIndex - 1) + vbTab 'get slot number from combo box [1]
                If tbRecipeName.Text.Length > 20 Then
                    strTxData = strTxData + tbRecipeName.Text.Substring(0, 20) + vbTab     'limit recipe name string to 20 characters [2]
                Else
                    strTxData = strTxData + tbRecipeName.Text + vbTab     'limit recipe name string to 20 characters [2]
                End If
            End If
            strTxData = strTxData + tbDoughIn.Text + vbTab 'Mash dough-in temp [3]
            strTxData = strTxData + tbDoughTime.Text + vbTab 'Dough in time [4]
            strTxData = strTxData + tbProteinTemp.Text + vbTab  '[5]
            strTxData = strTxData + tbProteinTime.Text + vbTab  '[6]
            strTxData = strTxData + tbSacchTemp.Text + vbTab    '[7]
            strTxData = strTxData + tbSacchTime.Text + vbTab    '[8]
            strTxData = strTxData + tbMOtemp.Text + vbTab       '[9]
            strTxData = strTxData + tbMOtime.Text + vbTab       '[10]
            strTxData = strTxData + tbSpargeTemp.Text + vbTab   '[11]
            strTxData = strTxData + tbDelay.Text + vbTab        '[12]
            strTxData = strTxData + tbHLsetpoint.Text + vbTab   '[13]
            strTxData = strTxData + tbVol.Text + vbTab          '[14]
            strTxData = strTxData + tbGrainWeight.Text + vbTab  '[15]
            strTxData = strTxData + tbBoilTotal.Text + vbTab    '[16]
            strTxData = strTxData + tbMashRatio.Text + vbTab    '[17]
            strTxData = strTxData + tbPitchTemp.Text + vbTab    '[18]
            Dim intAddns As Integer = 0
            If cbAddBoil.Checked = True Then
                intAddns = intAddns + 1
            End If
            If cbAdd105.Checked = True Then
                intAddns = intAddns + 2
            End If
            If cbAdd90.Checked = True Then
                intAddns = intAddns + 4
            End If
            If cbAdd75.Checked = True Then
                intAddns = intAddns + 8
            End If
            If cbAdd60.Checked = True Then
                intAddns = intAddns + 16
            End If
            If cbAdd45.Checked = True Then
                intAddns = intAddns + 32
            End If
            If cbAdd30.Checked = True Then
                intAddns = intAddns + 64
            End If
            If cbAdd20.Checked = True Then
                intAddns = intAddns + 128
            End If
            If cbAdd15.Checked = True Then
                intAddns = intAddns + 256
            End If
            If cbAdd10.Checked = True Then
                intAddns = intAddns + 512
            End If
            If cbAdd5.Checked = True Then
                intAddns = intAddns + 1024
            End If
            If cbAdd0.Checked = True Then
                intAddns = intAddns + 2048
            End If

            strTxData = strTxData + Str(intAddns) + vbTab 'boil additions bit mask (need to implement algorithm)  [19]
            strTxData = strTxData + tbGrainTemp.Text + vbCr    '[20]
        ElseIf Settings.asBTversion = "BT2" Then
            'BrewTroller 2.x program
            strTxData = "SET_PROG+"      'command [0]
            strTxData &= Str(cboBTrecipeSlot.SelectedIndex) & "+" 'get slot number from combo box [1]
            Dim strName As String = tbRecipeName.Text
            strName &= "                    "
            strName = strName.Substring(0, 20)  'limit recipe name string to 20 characters [2]
            strTxData &= strName & "+"
            strTxData &= tbDoughIn.Text & "+" 'Mash dough-in temp [3]
            strTxData &= tbDoughTime.Text & "+" 'Dough in time [4]
            strTxData &= tb2AcidTemp.Text & "+"   'Acid Temp [5]
            strTxData &= tb2AcidTime.Text & "+"   'Acid time [6]
            strTxData &= tbProteinTemp.Text & "+"  '[7]
            strTxData &= tbProteinTime.Text & "+"  '[8]
            strTxData &= tbSacchTemp.Text & "+"    '[9]
            strTxData &= tbSacchTime.Text & "+"    '[10]
            strTxData &= tb2Sacch2Temp.Text & "+"     '[11]
            strTxData &= tb2Sacch2Time.Text & "+"     '[12]
            strTxData &= tbMOtemp.Text & "+"       '[13]
            strTxData &= tbMOtime.Text & "+"       '[14]
            strTxData &= tbSpargeTemp.Text & "+"   '[15]
            'strTxData = strTxData + tbDelay.Text + vbTab        - not used in 2.x
            strTxData &= tbHLsetpoint.Text & "+"   '[16]
            strTxData &= tbVol.Text & "+"          '[17]"
            strTxData &= tbGrainWeight.Text & "+"  '[18]
            strTxData &= tbBoilTotal.Text & "+"    '[19]
            strTxData &= tbMashRatio.Text & "+"    '[20]
            strTxData &= tbPitchTemp.Text & "+"    '[21]
            Dim intAddns As Integer = 0
            If cbAddBoil.Checked = True Then
                intAddns = intAddns + 1
            End If
            If cbAdd105.Checked = True Then
                intAddns = intAddns + 2
            End If
            If cbAdd90.Checked = True Then
                intAddns = intAddns + 4
            End If
            If cbAdd75.Checked = True Then
                intAddns = intAddns + 8
            End If
            If cbAdd60.Checked = True Then
                intAddns = intAddns + 16
            End If
            If cbAdd45.Checked = True Then
                intAddns = intAddns + 32
            End If
            If cbAdd30.Checked = True Then
                intAddns = intAddns + 64
            End If
            If cbAdd20.Checked = True Then
                intAddns = intAddns + 128
            End If
            If cbAdd15.Checked = True Then
                intAddns = intAddns + 256
            End If
            If cbAdd10.Checked = True Then
                intAddns = intAddns + 512
            End If
            If cbAdd5.Checked = True Then
                intAddns = intAddns + 1024
            End If
            If cbAdd0.Checked = True Then
                intAddns = intAddns + 2048
            End If

            strTxData &= Str(intAddns) & "-" 'boil additions bit mask (need to implement algorithm)  [22]
            'strTxData = strTxData + tbGrainTemp.Text + vbCr    - not used in 2.x

        End If

        AddToTXstack(strTxData)

        'request confirmation from BT
        blnGetProg(cboBTrecipeSlot.SelectedIndex) = True
        'Sleep(5000)

        'confirm data ok
        'blnLoadBTrecipe = True
        'intLoadBTrecipeNum = cboBTrecipeSlot.SelectedIndex
        'AddToTXstack("GET_PROG" + vbTab + Str(cboBTrecipeSlot.SelectedIndex) + vbCr)

    End Sub

    Private Sub validateRecipe()

        'validate data fields needed for BrewTroller 1.x recipe settings

        If tbVol.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Batch Volume field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbGrainWeight.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Grain weight field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If Settings.asBTversion = "BT1" Then
            If tbGrainTemp.ForeColor = Color.Red Then
                tsslMiscInfo.Text = "Grain temperature field contains invalid data"
                tsslMiscInfo.Visible = True
                tmrMessages.Interval = 20000
                tmrMessages.Enabled = True
                Beep()
                Exit Sub
            End If
        End If

        If tbMashRatio.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Mash Ratio field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbDoughIn.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Dough In temperature field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbDoughTime.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Dough In time field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbProteinTemp.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Protein temperature field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbProteinTime.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Protein time field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbSacchTemp.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Sacch temperature field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbSacchTime.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Sacch time field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbMOtemp.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Mash Out temperature field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbMOtime.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Mash Out time field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbSpargeTemp.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Sparge temperature field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbBoilTotal.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Boil time field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        If tbPitchTemp.ForeColor = Color.Red Then
            tsslMiscInfo.Text = "Pitch temperature field contains invalid data"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 20000
            tmrMessages.Enabled = True
            Beep()
            Exit Sub
        End If

        'validate data fields for BrewTroller 2.x recipes if needed
        If Settings.asBTversion = "BT2" Then
            If tb2AcidTemp.ForeColor = Color.Red Then
                tsslMiscInfo.Text = "Acid temperature field contains invalid data"
                tsslMiscInfo.Visible = True
                tmrMessages.Interval = 20000
                tmrMessages.Enabled = True
                Beep()
                Exit Sub
            End If
            If tb2AcidTime.ForeColor = Color.Red Then
                tsslMiscInfo.Text = "Acid time field contains invalid data"
                tsslMiscInfo.Visible = True
                tmrMessages.Interval = 20000
                tmrMessages.Enabled = True
                Beep()
                Exit Sub
            End If
            If tb2Sacch2Temp.ForeColor = Color.Red Then
                tsslMiscInfo.Text = "Sacch2 temperature field contains invalid data"
                tsslMiscInfo.Visible = True
                tmrMessages.Interval = 20000
                tmrMessages.Enabled = True
                Beep()
                Exit Sub
            End If
            If tb2Sacch2Time.ForeColor = Color.Red Then
                tsslMiscInfo.Text = "Sacch2 time field contains invalid data"
                tsslMiscInfo.Visible = True
                tmrMessages.Interval = 20000
                tmrMessages.Enabled = True
                Beep()
                Exit Sub
            End If

        End If


    End Sub

    Private Sub btnGetRecipeFromBT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetRecipeFromBT.Click

        blnLoadBTrecipe = True
        intLoadBTrecipeNum = cboBTrecipeSlot.SelectedIndex
        If Settings.asBTversion = "BT1" Then
            If intLoadBTrecipeNum = 0 Then
                'get autobrew settings
                AddToTXstack("GET_ABSET" + vbCr)
            Else
                'get regular program slot settings
                AddToTXstack("GET_PROG" + vbTab + Str(intLoadBTrecipeNum - 1) + vbCr)
            End If
        ElseIf Settings.asBTversion = "BT2" Then
            'get regular program slot settings
            AddToTXstack("GET_PROG" + vbTab + Str(intLoadBTrecipeNum) + vbCr)
        End If

    End Sub

    Private Sub tmrSendtoBT_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrSendtoBT.Tick

        'is enabled only if a serial connection is open
        'checks stack to see if there are commands waiting
        'sends valid command to BrewTroller if available

        Dim strSerCommand As String = getFromTXstack()
        If strSerCommand <> "False" Then
            sendBTstring(strSerCommand) 'transmit message
        End If

        Exit Sub

        ''no longer needed



        'If My.Settings.asBlnUpdateValveProfile Then
        '    'we need to update the BrewTroller with new valve profiles
        '    Dim vlvMask As String = Nothing

        '    Select Case vlvProf
        '        Case 0
        '            vlvMask = My.Settings.asVP1
        '        Case 1
        '            vlvMask = My.Settings.asVP2
        '        Case 2
        '            vlvMask = My.Settings.asVP3
        '        Case 3
        '            vlvMask = My.Settings.asVP4
        '        Case 4
        '            vlvMask = My.Settings.asVP5
        '        Case 5
        '            vlvMask = My.Settings.asVP6
        '        Case 6
        '            vlvMask = My.Settings.asVP7
        '        Case 7
        '            vlvMask = My.Settings.asVP8
        '        Case 8
        '            vlvMask = My.Settings.asVP9
        '        Case 9
        '            vlvMask = My.Settings.asVP10
        '        Case 10
        '            vlvMask = My.Settings.asVP11
        '        Case 11
        '            vlvMask = My.Settings.asVP12
        '            'clear flag
        '            My.Settings.asBlnUpdateValveProfile = False
        '    End Select
        '    'write new profile to BT
        '    AddToTXstack("SET_VLVP" + vbTab + vlvProf.ToString + vbTab + vlvMask + vbCrLf)
        '    'If vlvProf = intPrimActiveValveProfile Then
        '    '    'send act_vlv command - not sure why we need to do this - a BT bug perhaps?
        '    '    AddToTXstack("ACT_VLV" + vbTab + vlvMask + vbCrLf)
        '    'End If
        '    If My.Settings.asBlnUpdateValveProfile Then
        '        vlvProf += 1
        '    Else
        '        vlvProf = 0
        '    End If
        '    Exit Sub 'only allow a single message to be sent from the queue during one timer tick
        'End If

    End Sub


    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Dim strTx As String = tbTxStr.Text + vbCr
        strTx = strTx.ToUpper()
        AddToTXstack(strTx)
        tbTxStr.Text = ""
    End Sub


    Private Sub btnSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

        'send select command to BT
        'Dim strTx As String = "SELECT" & vbTab
        'If btnSelect.Text = "Continue" Then
        '    'option to select is 0
        '    strTx &= "0"
        'ElseIf btnSelect.Text = "Select Choice" Then
        '    'get menu option
        '    Dim intMenuChoice As Integer
        '    intMenuChoice = cboMenuOptions.SelectedIndex
        '    strTx &= CStr(intMenuChoice)
        'End If

        ''disable menu options until another prompt command has been received
        'btnSelect.Enabled = False
        'cboMenuOptions.Enabled = False
        'lblMenuTitle.Text = "No active menu"
        'AddToTXstack(strTx & vbCr)
    End Sub

    Private Sub btnExitBT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

        'If btnExitBT.Text = "Exit" Then
        'we need to confirm exit - add information under BTstatus
        '    Dim strConfirm As String
        '    strConfirm = "Exiting will reset all outputs." & vbCrLf
        '    strConfirm &= "Please confirm if you wish to continue ..."
        'End If

        Dim strTx As String
        strTx = "SET_PLR" & vbTab & "0" & vbCr    'sets the power loss reset to 'none'
        strTx &= "RESET" & vbTab & "SURE" & vbCr    'resets the BrewTroller so we can go back to the start menu
        AddToTXstack(strTx)   'and sends it to the BT

    End Sub

    Private Sub btnBTcontrolUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBTcontrolUpdate.Click
        Dim intControlStep As Integer
        intControlStep = cboControlStep.SelectedIndex

        'set up transmit string and send it
        Dim strTx As String

        If intControlStep = 0 Then
            'we want to reset the BT and present the splash screen
            strTx = "SET_PLR" & vbTab & "0" & vbCr  'set BT so that it auto resets into AutoBrew mode
        ElseIf intControlStep = 14 Then
            'we want to select Brew Monitor, not an AB step
            strTx = "SET_PLR" & vbTab & "2" & vbCr  'set BT so that it auto resets into AutoBrew mode
        Else
            strTx = "SET_PLR" & vbTab & "1" & vbCr  'set BT so that it auto resets into AutoBrew mode
            strTx &= "SET_ABSTEP" & vbTab & CStr(intControlStep) & vbCr 'set the AutoBrew step
        End If

        strTx &= "RESET" & vbTab & "SURE" & vbCr    'and reset the BT

        'now send command
        AddToTXstack(strTx)
    End Sub

    Private Sub cboLoadedRecipe_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboLoadedRecipe.SelectedIndexChanged

        Call GetRecipeXML()

        'loads values from selected recipe file
        'Call getHops()
    End Sub

    Private Sub tbMashRatio_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbMashRatio.TextChanged
        Dim tb As New TextBox
        tb = tbMashRatio
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next
    End Sub

    Private Sub tbDoughIn_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim tb As New TextBox
        tb = tbDoughIn
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next
    End Sub

    Private Sub tbVol_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbVol.TextChanged
        Dim tb As New TextBox
        tb = tbVol
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next
    End Sub

    Private Sub tbGrainWeight_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbGrainWeight.TextChanged
        Dim tb As New TextBox
        tb = tbGrainWeight
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbGrainTemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbGrainTemp.TextChanged
        Dim tb As New TextBox
        tb = tbGrainTemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbBoilTotal_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbBoilTotal.TextChanged
        Dim tb As New TextBox
        tb = tbBoilTotal
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbPitchTemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbPitchTemp.TextChanged
        Dim tb As New TextBox
        tb = tbPitchTemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbDelay_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim tb As New TextBox
        tb = tbDelay
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbDoughTime_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim tb As New TextBox
        tb = tbDoughTime
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbProteinTemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbProteinTemp.TextChanged
        Dim tb As New TextBox
        tb = tbProteinTemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbProteinTime_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbProteinTime.TextChanged
        Dim tb As New TextBox
        tb = tbProteinTime
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbSacchTemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbSacchTemp.TextChanged
        Dim tb As New TextBox
        tb = tbSacchTemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbSacchTime_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbSacchTime.TextChanged
        Dim tb As New TextBox
        tb = tbSacchTime
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbMOtemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbMOtemp.TextChanged
        Dim tb As New TextBox
        tb = tbMOtemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbMOtime_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbMOtime.TextChanged
        Dim tb As New TextBox
        tb = tbMOtime
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tbSpargeTemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbSpargeTemp.TextChanged
        Dim tb As New TextBox
        tb = tbSpargeTemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub Label39_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label39.Click

    End Sub

    Private Sub btnIM0_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIM0.Click

    End Sub

    Private Sub btnLogPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogPath.Click

        'open file dialog
        Dim MyLogPath As New FolderBrowserDialog
        With MyLogPath
            ' Desktop is the root folder in the dialog.
            .RootFolder = Environment.SpecialFolder.Desktop
            ' Select the Application.StartupPath()  directory on entry.
            .SelectedPath = Application.StartupPath()
            ' Prompt the user with a custom message.
            .Description = "Select the path to store your log files"
            If .ShowDialog = DialogResult.OK Then
                ' Display the selected folder if the user clicked on the OK button.
                tbLogFilePath.Text = .SelectedPath
                'and indicate path is user selected
                My.Settings.asLogPathSet = True
            End If
        End With
        SaveMySettings()
    End Sub

    Private Sub btnXMLpath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnXMLpath.Click

        'open file dialog
        Dim MyXMLPath As New FolderBrowserDialog
        With MyXMLPath
            ' Desktop is the root folder in the dialog.
            .RootFolder = Environment.SpecialFolder.Desktop
            ' Select the Application.StartupPath()  directory on entry.
            .SelectedPath = Application.StartupPath()
            ' Prompt the user with a custom message.
            .Description = "Select the path to store your log files"
            If .ShowDialog = DialogResult.OK Then
                ' Display the selected folder if the user clicked on the OK button.
                tbXMLpath.Text = .SelectedPath
                'and indicate user selected path
                My.Settings.asXMLPathSet = True
            End If
        End With
        SaveMySettings()

    End Sub


    Private Sub cbGoLive_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbGoLive.CheckedChanged

        If cbGoLive.Checked = True Then
            Dim SessionFile As String = My.Settings.asLogFilePath + "\" + Format(Now, "yyMMdd") + ".btd"
            If File.Exists(SessionFile) Then
                My.Settings.asStrGraphDataFile = SessionFile
            End If
            CreateNewGraph()
        End If

    End Sub

    Private Sub tbHLsetpoint_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbHLsetpoint.TextChanged
        Dim tb As New TextBox
        tb = tbHLsetpoint
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub btnSaveSettings_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSaveSettings.Click
        SaveMySettings()
        LoadMySettings()
        tcMain.SelectedTab = tpSetttings
    End Sub

    Private Sub tmrMessages_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrMessages.Tick

        'message disappears at timer tick
        tsslMiscInfo.Visible = False
        tmrMessages.Enabled = False

    End Sub

    Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        wbPanel.Refresh()
    End Sub

    Private Sub lblHLTset_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        btnHLTspDn.Visible = True
        btnHLTspUp.Visible = True
    End Sub

    Private Sub tbFTPusername_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbFTPusername.TextChanged
        My.Settings.asBlnFTPsupportFilesOK = False    'resends ftp support files by default
    End Sub

    Private Sub cbShowComms_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbShowComms.CheckedChanged
        'MsgBox("Please restart BTremote to allow changes to take effect.", MsgBoxStyle.Information, "Restart needed")
        'If My.Settings.asShowCommsTAB = False Then
        '    'hide tab
        '    tcMain.TabPages.Remove(tpComm)
        'Else
        '    tcMain.TabPages.Add(tpComm)
        'End If
    End Sub

    Private Sub cbShowControl_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbShowControl.CheckedChanged
        'MsgBox("Please restart BTremote to allow changes to take effect.", MsgBoxStyle.Information, "Restart needed")
        'If My.Settings.asShowControlTAB = False Then
        '    'hide tab
        '    tcMain.TabPages.Remove(tpControl)
        'Else
        '    tcMain.TabPages.Add(tpControl)
        'End If
    End Sub

    Private Sub cbShowGraph_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbShowGraph.CheckedChanged
        'MsgBox("Please restart BTremote to allow changes to take effect.", MsgBoxStyle.Information, "Restart needed")
        'If My.Settings.asShowGraphTAB = False Then
        '    'hide tab
        '    tcMain.TabPages.Remove(tpGraph)
        'Else
        '    tcMain.TabPages.Add(tpGraph)
        'End If
    End Sub

    Private Sub btnVP3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

    Private Sub btnV4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

    Private Sub cboBTnumValves_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboBTnumValves.SelectedIndexChanged
        Dim intSelectedIndex = sender.SelectedIndex

        If intSelectedIndex = 0 Then
            'show 8 outputs
            tbV9.Visible = False
            cbV9.Visible = False
            tbV10.Visible = False
            cbV10.Visible = False
            tbV11.Visible = False
            cbV11.Visible = False
            tbV12.Visible = False
            cbV12.Visible = False
            tbV13.Visible = False
            cbV13.Visible = False
            tbV14.Visible = False
            cbV14.Visible = False
            tbV15.Visible = False
            cbV15.Visible = False
            tbV16.Visible = False
            cbV16.Visible = False
            tbV17.Visible = False
            cbV17.Visible = False
            tbV18.Visible = False
            cbV18.Visible = False
            tbV19.Visible = False
            cbV19.Visible = False
            tbV20.Visible = False
            cbV20.Visible = False
            tbV21.Visible = False
            cbV21.Visible = False
            tbV22.Visible = False
            cbV22.Visible = False
            tbV23.Visible = False
            cbV23.Visible = False
            tbV24.Visible = False
            cbV24.Visible = False
            tbV25.Visible = False
            cbV25.Visible = False
            tbV26.Visible = False
            cbV26.Visible = False
            tbV27.Visible = False
            cbV27.Visible = False
            tbV28.Visible = False
            cbV28.Visible = False
            tbV29.Visible = False
            cbV29.Visible = False
            tbV30.Visible = False
            cbV30.Visible = False
            tbV31.Visible = False
            cbV31.Visible = False
            tbV32.Visible = False
            cbV32.Visible = False

        ElseIf intSelectedIndex = 1 Then
            'show 11 outputs
            tbV9.Visible = True
            cbV9.Visible = True
            tbV10.Visible = True
            cbV10.Visible = True
            tbV11.Visible = True
            cbV11.Visible = True
            tbV12.Visible = False
            cbV12.Visible = False
            tbV13.Visible = False
            cbV13.Visible = False
            tbV14.Visible = False
            cbV14.Visible = False
            tbV15.Visible = False
            cbV15.Visible = False
            tbV16.Visible = False
            cbV16.Visible = False
            tbV17.Visible = False
            cbV17.Visible = False
            tbV18.Visible = False
            cbV18.Visible = False
            tbV19.Visible = False
            cbV19.Visible = False
            tbV20.Visible = False
            cbV20.Visible = False
            tbV21.Visible = False
            cbV21.Visible = False
            tbV22.Visible = False
            cbV22.Visible = False
            tbV23.Visible = False
            cbV23.Visible = False
            tbV24.Visible = False
            cbV24.Visible = False
            tbV25.Visible = False
            cbV25.Visible = False
            tbV26.Visible = False
            cbV26.Visible = False
            tbV27.Visible = False
            cbV27.Visible = False
            tbV28.Visible = False
            cbV28.Visible = False
            tbV29.Visible = False
            cbV29.Visible = False
            tbV30.Visible = False
            cbV30.Visible = False
            tbV31.Visible = False
            cbV31.Visible = False
            tbV32.Visible = False
            cbV32.Visible = False
        ElseIf intSelectedIndex = 2 Then
            'show 16 outputs
            tbV9.Visible = True
            cbV9.Visible = True
            tbV10.Visible = True
            cbV10.Visible = True
            tbV11.Visible = True
            cbV11.Visible = True
            tbV12.Visible = True
            cbV12.Visible = True
            tbV13.Visible = True
            cbV13.Visible = True
            tbV14.Visible = True
            cbV14.Visible = True
            tbV15.Visible = True
            cbV15.Visible = True
            tbV16.Visible = True
            cbV16.Visible = True
            tbV17.Visible = False
            cbV17.Visible = False
            tbV18.Visible = False
            cbV18.Visible = False
            tbV19.Visible = False
            cbV19.Visible = False
            tbV20.Visible = False
            cbV20.Visible = False
            tbV21.Visible = False
            cbV21.Visible = False
            tbV22.Visible = False
            cbV22.Visible = False
            tbV23.Visible = False
            cbV23.Visible = False
            tbV24.Visible = False
            cbV24.Visible = False
            tbV25.Visible = False
            cbV25.Visible = False
            tbV26.Visible = False
            cbV26.Visible = False
            tbV27.Visible = False
            cbV27.Visible = False
            tbV28.Visible = False
            cbV28.Visible = False
            tbV29.Visible = False
            cbV29.Visible = False
            tbV30.Visible = False
            cbV30.Visible = False
            tbV31.Visible = False
            cbV31.Visible = False
            tbV32.Visible = False
            cbV32.Visible = False
        ElseIf intSelectedIndex = 3 Then
            'show 24 outputs
            tbV9.Visible = True
            cbV9.Visible = True
            tbV10.Visible = True
            cbV10.Visible = True
            tbV11.Visible = True
            cbV11.Visible = True
            tbV12.Visible = True
            cbV12.Visible = True
            tbV13.Visible = True
            cbV13.Visible = True
            tbV14.Visible = True
            cbV14.Visible = True
            tbV15.Visible = True
            cbV15.Visible = True
            tbV16.Visible = True
            cbV16.Visible = True
            tbV17.Visible = True
            cbV17.Visible = True
            tbV18.Visible = True
            cbV18.Visible = True
            tbV19.Visible = True
            cbV19.Visible = True
            tbV20.Visible = True
            cbV20.Visible = True
            tbV21.Visible = True
            cbV21.Visible = True
            tbV22.Visible = True
            cbV22.Visible = True
            tbV23.Visible = True
            cbV23.Visible = True
            tbV24.Visible = True
            cbV24.Visible = True
            tbV25.Visible = False
            cbV25.Visible = False
            tbV26.Visible = False
            cbV26.Visible = False
            tbV27.Visible = False
            cbV27.Visible = False
            tbV28.Visible = False
            cbV28.Visible = False
            tbV29.Visible = False
            cbV29.Visible = False
            tbV30.Visible = False
            cbV30.Visible = False
            tbV31.Visible = False
            cbV31.Visible = False
            tbV32.Visible = False
            cbV32.Visible = False
        ElseIf intSelectedIndex = 4 Then
            'show all 32 outputs
            tbV9.Visible = True
            cbV9.Visible = True
            tbV10.Visible = True
            cbV10.Visible = True
            tbV11.Visible = True
            cbV11.Visible = True
            tbV12.Visible = True
            cbV12.Visible = True
            tbV13.Visible = True
            cbV13.Visible = True
            tbV14.Visible = True
            cbV14.Visible = True
            tbV15.Visible = True
            cbV15.Visible = True
            tbV16.Visible = True
            cbV16.Visible = True
            tbV17.Visible = True
            cbV17.Visible = True
            tbV18.Visible = True
            cbV18.Visible = True
            tbV19.Visible = True
            cbV19.Visible = True
            tbV20.Visible = True
            cbV20.Visible = True
            tbV21.Visible = True
            cbV21.Visible = True
            tbV22.Visible = True
            cbV22.Visible = True
            tbV23.Visible = True
            cbV23.Visible = True
            tbV24.Visible = True
            cbV24.Visible = True
            tbV25.Visible = True
            cbV25.Visible = True
            tbV26.Visible = True
            cbV26.Visible = True
            tbV27.Visible = True
            cbV27.Visible = True
            tbV28.Visible = True
            cbV28.Visible = True
            tbV29.Visible = True
            cbV29.Visible = True
            tbV30.Visible = True
            cbV30.Visible = True
            tbV31.Visible = True
            cbV31.Visible = True
            tbV32.Visible = True
            cbV32.Visible = True
        End If
    End Sub

    Private Sub FrmControlPanel_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        Dim w As Integer = Me.Width
        Dim h As Integer = Me.ssMain.Location.Y
        'Dim ws As Integer=Me.

        'cbSerialConnect.Location = New Point(1024 - 126, h + 5)
        'cboPort.Location = New Point(1024 - 197, h - 51)

    End Sub

    Private Sub tbtxstr_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles tbTxStr.KeyDown
        If e.KeyCode = Keys.Enter Then
            btnSend_Click(Me, EventArgs.Empty)
        End If
    End Sub

    '************************************
    '                                   *
    '          TIMER BUTTONS            *
    '                                   *
    '************************************

    Private Sub btnTimerStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTimerStop.Click
        AddToTXstack("SET_TIMERVALUE" + vbTab + "0" + vbCr + vbCr + "SET_TIMERSTATUS" + vbTab + "0" + vbCr) 'send it to the BT

    End Sub

    Private Sub btnTimRunPause_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTimRunPause.Click
        If btnTimRunPause.Text = ">" Then
            btnTimRunPause.Text = "||"
            'btnTimRunPause.BackColor = Color.GreenYellow
            AddToTXstack("SET_TIMERSTATUS+1-")
        ElseIf btnTimRunPause.Text = "||" Then
            btnTimRunPause.Text = ">"
            'btnTimRunPause.BackColor = Color.OrangeRed
            AddToTXstack("SET_TIMERSTATUS+0-")
        End If

    End Sub

    Private Sub btnTimerUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTimerUp.Click

        Dim lngTimeLeft As Long
        If IsNumeric(DisplayInfo(DI_TIME_MILLIS)) Then
            lngTimeLeft = CLng(DisplayInfo(DI_TIME_MILLIS)) + 60000 'adds 1 minute
        Else
            lngTimeLeft = 60000
        End If
        AddToTXstack("SET_TIMERVALUE" + vbTab + lngTimeLeft.ToString + vbCr) 'send it to the BT

    End Sub
    Private Sub btnTimerDwn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTimerDwn.Click

        Dim lngTimeLeft As Long
        If IsNumeric(DisplayInfo(DI_TIME_MILLIS)) Then
            lngTimeLeft = CLng(DisplayInfo(DI_TIME_MILLIS)) - 60000 'subtracts 1 minute
            If lngTimeLeft < 0 Then lngTimeLeft = 0
        Else
            lngTimeLeft = 0
        End If
        AddToTXstack("SET_TIMERVALUE" + vbTab + lngTimeLeft.ToString + vbCr) 'send it to the BT

    End Sub

    Private Sub btnTimerInc10_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

        Dim lngTimeLeft As Long
        If IsNumeric(DisplayInfo(DI_TIME_MILLIS)) Then
            lngTimeLeft = CLng(DisplayInfo(DI_TIME_MILLIS)) + 600000 'adds 10 minutes
        Else
            lngTimeLeft = 600000
        End If
        AddToTXstack("SET_TIMERVALUE" + vbTab + lngTimeLeft.ToString + vbCr) 'send it to the BT

    End Sub

    Private Sub btnTimerDec10_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

        Dim lngTimeLeft As Long
        If IsNumeric(DisplayInfo(DI_TIME_MILLIS)) Then
            lngTimeLeft = CLng(DisplayInfo(DI_TIME_MILLIS)) - 600000 'subtracts 10 minutes
            If lngTimeLeft < 0 Then lngTimeLeft = 0
        Else
            lngTimeLeft = 0
        End If
        AddToTXstack("SET_TIMERVALUE" + vbTab + lngTimeLeft.ToString + vbCr) 'send it to the BT

    End Sub

    'Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    '    '*******************
    '    'NEED error control for updownbutton time
    '    '***********************

    '    Dim lngSetTime As Long
    '    lngSetTime = NumericUpDown1.Value * 3600000 + NumericUpDown2.Value * 60000
    '    AddToTXstack("SET_TIMERVALUE" + vbTab + lngSetTime.ToString + vbCr) 'send it to the BT
    '    NumericUpDown1.Value = 0
    '    NumericUpDown2.Value = 0

    'End Sub

    Private Sub rbValveAllowControl_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    End Sub

    Private Sub ValveBtns(ByVal Mode As String)
        Mode = "unlock"
        If Mode = "lock" Then
            cbV1.Enabled = False
            cbV2.Enabled = False
            cbV3.Enabled = False
            cbV4.Enabled = False
            cbV5.Enabled = False
            cbV6.Enabled = False
            cbV7.Enabled = False
            cbV8.Enabled = False
            cbV9.Enabled = False
            cbV10.Enabled = False
            cbV11.Enabled = False
            cbV12.Enabled = False
            cbV13.Enabled = False
            cbV14.Enabled = False
            cbV15.Enabled = False
            cbV16.Enabled = False
            cbV17.Enabled = False
            cbV18.Enabled = False
            cbV19.Enabled = False
            cbV20.Enabled = False
            cbV21.Enabled = False
            cbV22.Enabled = False
            cbV23.Enabled = False
            cbV24.Enabled = False
            cbV25.Enabled = False
            cbV26.Enabled = False
            cbV27.Enabled = False
            cbV28.Enabled = False
            cbV29.Enabled = False
            cbV30.Enabled = False
            cbV31.Enabled = False
            cbV32.Enabled = False
        Else
            'enable user changes on valve buttons
            cbV1.Enabled = True
            cbV2.Enabled = True
            cbV3.Enabled = True
            cbV4.Enabled = True
            cbV5.Enabled = True
            cbV6.Enabled = True
            cbV7.Enabled = True
            cbV8.Enabled = True
            cbV9.Enabled = True
            cbV10.Enabled = True
            cbV11.Enabled = True
            cbV12.Enabled = True
            cbV13.Enabled = True
            cbV14.Enabled = True
            cbV15.Enabled = True
            cbV16.Enabled = True
            cbV17.Enabled = True
            cbV18.Enabled = True
            cbV19.Enabled = True
            cbV20.Enabled = True
            cbV21.Enabled = True
            cbV22.Enabled = True
            cbV23.Enabled = True
            cbV24.Enabled = True
            cbV25.Enabled = True
            cbV26.Enabled = True
            cbV27.Enabled = True
            cbV28.Enabled = True
            cbV29.Enabled = True
            cbV30.Enabled = True
            cbV31.Enabled = True
            cbV32.Enabled = True

        End If
    End Sub

    Private Sub btnControl1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl1.Click
        AddToTXstack(My.Settings.asControlString1)
    End Sub

    Private Sub btnControl2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl2.Click
        AddToTXstack(My.Settings.asControlString2)
    End Sub

    Private Sub btnControl4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl4.Click
        AddToTXstack(My.Settings.asControlString4)
    End Sub

    Private Sub btnControl3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl3.Click
        AddToTXstack(My.Settings.asControlString3)
    End Sub

    Private Sub btnControl5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl5.Click
        AddToTXstack(My.Settings.asControlString5)
    End Sub

    Private Sub btnControl6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl6.Click
        AddToTXstack(My.Settings.asControlString6)
    End Sub

    Private Sub btnControl7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl7.Click
        AddToTXstack(My.Settings.asControlString7)
    End Sub

    Private Sub btnControl8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnControl8.Click
        AddToTXstack(My.Settings.asControlString8)
    End Sub


    Private Sub btnStepNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStepNext.Click

        Dim intControlStep As Integer
        If IsNumeric(DisplayInfo(DI_ABSTEP_NUM)) Then
            intControlStep = DisplayInfo(DI_ABSTEP_NUM)
            intControlStep += 1 'increment step
            If intControlStep > 13 Then intControlStep = 0
        Else
            intControlStep = 0
        End If

        'set up transmit string and send it
        Dim strTx As String

        If intControlStep = 0 Then
            'we want to reset the BT and present the splash screen
            strTx = "SET_PLR" & vbTab & "0" & vbCr  'set BT so that it auto resets into AutoBrew mode
        ElseIf intControlStep = 14 Then
            'we want to select Brew Monitor, not an AB step
            strTx = "SET_PLR" & vbTab & "2" & vbCr  'set BT so that it auto resets into AutoBrew mode
        Else
            strTx = "SET_PLR" & vbTab & "1" & vbCr  'set BT so that it auto resets into AutoBrew mode
            strTx &= "SET_ABSTEP" & vbTab & CStr(intControlStep) & vbCr 'set the AutoBrew step
        End If

        strTx &= "RESET" & vbTab & "SURE" & vbCr    'and reset the BT

        'now send command
        AddToTXstack(strTx)

    End Sub

    Private Sub btnStepPrev_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStepPrev.Click

        Dim intControlStep As Integer
        If IsNumeric(DisplayInfo(DI_ABSTEP_NUM)) Then
            intControlStep = DisplayInfo(DI_ABSTEP_NUM)
            intControlStep -= 1 'decrement step
            If intControlStep < 0 Then intControlStep = 13
        Else
            intControlStep = 0
        End If


        'set up transmit string and send it
        Dim strTx As String

        If intControlStep = 0 Then
            'we want to reset the BT and present the splash screen
            strTx = "SET_PLR" & vbTab & "0" & vbCr  'set BT so that it auto resets into AutoBrew mode
        ElseIf intControlStep = 14 Then
            'we want to select Brew Monitor, not an AB step
            strTx = "SET_PLR" & vbTab & "2" & vbCr  'set BT so that it auto resets into AutoBrew mode
        Else
            strTx = "SET_PLR" & vbTab & "1" & vbCr  'set BT so that it auto resets into AutoBrew mode
            strTx &= "SET_ABSTEP" & vbTab & CStr(intControlStep) & vbCr 'set the AutoBrew step
        End If

        strTx &= "RESET" & vbTab & "SURE" & vbCr    'and reset the BT

        'now send command
        AddToTXstack(strTx)

    End Sub

    Private Sub btnHLTspUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHLTspUp.Click

        Dim intHLTUp As Integer = 0
        If IsNumeric(DataInfo(DI_HLT_SET)) Then
            intHLTUp = CInt(DataInfo(DI_HLT_SET))
        Else
            Exit Sub
        End If

        intHLTUp += 1
        AddToTXstack("SET_SETPOINT" + vbTab + "0" + vbTab + intHLTUp.ToString + vbCr)

    End Sub

    Private Sub btnHLTspDn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHLTspDn.Click

        Dim intHLTdn As Integer = 0
        If IsNumeric(DataInfo(DI_HLT_SET)) Then
            intHLTdn = CInt(DataInfo(DI_HLT_SET))
        Else
            Exit Sub
        End If

        intHLTdn -= 1
        If intHLTdn < 0 Then intHLTdn = 0
        AddToTXstack("SET_SETPOINT" + vbTab + "0" + vbTab + intHLTdn.ToString + vbCr)

    End Sub

    Private Sub btnMTspUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMTspUp.Click

        Dim intMashUp As Integer = 0
        If IsNumeric(DataInfo(DI_MASH_SET)) Then
            intMashUp = CInt(DataInfo(DI_MASH_SET))
        Else
            Exit Sub
        End If

        intMashUp += 1
        AddToTXstack("SET_SETPOINT" + vbTab + "1" + vbTab + intMashUp.ToString + vbCr)


    End Sub

    Private Sub btnMTspDn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMTspDn.Click

        Dim intMASHdn As Integer = 0
        If IsNumeric(DataInfo(DI_MASH_SET)) Then
            intMASHdn = CInt(DataInfo(DI_MASH_SET))
        Else
            Exit Sub
        End If

        intMASHdn -= 1
        If intMASHdn < 0 Then intMASHdn = 0
        AddToTXstack("SET_SETPOINT" + vbTab + "1" + vbTab + intMASHdn.ToString + vbCr)

    End Sub

    Private Sub btnKETspUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnKETspUp.Click

        Dim intKettleUp As Integer = 0
        If IsNumeric(DataInfo(DI_KET_SET)) Then
            intKettleUp = CInt(DataInfo(DI_KET_SET))
        Else
            Exit Sub
        End If

        intKettleUp += 1
        AddToTXstack("SET_SETPOINT" + vbTab + "2" + vbTab + intKettleUp.ToString + vbCr)

    End Sub

    Private Sub btnKETspDn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnKETspDn.Click

        Dim intKettleDn As Integer = 0
        If IsNumeric(DataInfo(DI_KET_SET)) Then
            intKettleDn = CInt(DataInfo(DI_KET_SET))
        Else
            Exit Sub
        End If

        intKettleDn -= 1
        If intKettleDn < 0 Then intKettleDn = 0
        AddToTXstack("SET_SETPOINT" + vbTab + "2" + vbTab + intKettleDn.ToString + vbCr)

    End Sub

#End Region

#Region "Functions"

    Private Function rotateNeedle(ByVal temp As Double) As Single

        'returns value for xml file to rotate needle gauge

        Dim dTop As Double
        Dim NeedleAngle As Single

        If temp > 60 Then
            dTop = temp - 60
            NeedleAngle = dTop * 2.266667
        Else
            dTop = 60 - temp
            NeedleAngle = -(dTop * 2.3)
        End If

        rotateNeedle = NeedleAngle

    End Function

    Private Function extractPMdata(ByVal strText As String, ByVal strStartText As String, ByVal intSkip As Integer, ByVal strEndText As String) As String

        Dim posnStart As Integer = 0
        Dim posnEnd As Integer = 0
        Dim strData As String = ""
        Dim newText As String = ""

        'find string
        posnStart = InStr(strText, strStartText, CompareMethod.Text)
        If posnStart > 0 Then
            'we have found it
            posnStart = posnStart + strStartText.Length + intSkip - 1   'new start position
            'truncate preceding part of string
            posnEnd = strText.Length - 1
            For currentIndex As Integer = posnStart To posnEnd
                newText = newText + strText(currentIndex)
            Next
            'now we look for first occurrence of end string
            posnEnd = InStr(newText, strEndText, CompareMethod.Text)
            If posnEnd > 0 Then
                'we have found our end point
                posnStart = 0
                posnEnd = posnEnd - 2
                For currentIndex As Integer = posnStart To posnEnd
                    strData = strData + newText(currentIndex)
                Next
                extractPMdata = Trim(strData)
            Else
                extractPMdata = ""
                Exit Function
            End If
        End If

    End Function

    Private Function extractPMdataBefore(ByVal strText As String, ByVal strEndBefore As String, ByVal intBackStep As Integer, ByVal intLength As Integer) As String

        Dim posnStart As Integer = 0
        Dim posnEnd As Integer = 0
        Dim strData As String = ""
        Dim newText As String = ""

        'find string
        posnEnd = InStr(strText, strEndBefore, CompareMethod.Text)
        If posnEnd > 0 Then
            'we have found it
            posnEnd = posnEnd - intBackStep - 2   'new end position
            posnStart = posnEnd - intLength + 1 'new start position
            'get new string
            For currentIndex As Integer = posnStart To posnEnd
                newText = newText + strText(currentIndex)
            Next
            extractPMdataBefore = Trim(newText)
        Else
            extractPMdataBefore = ""
            Exit Function
        End If

    End Function

    Private Function extractPMdataLength(ByVal strText As String, ByVal strStartText As String, ByVal intSkip As Integer, ByVal intLength As Integer) As String

        Dim posnStart As Integer = 0
        Dim posnEnd As Integer = 0
        Dim strData As String = ""
        Dim newStrText As String = strText

        'find string
        posnStart = InStr(strText, strStartText, CompareMethod.Text)

        If posnStart > 0 Then
            'we have our string, extract it

            'alter start and end positions to get text between
            posnStart = posnStart + strStartText.Length - 1 + intSkip
            posnEnd = posnStart + intLength - 1
            For currentIndex As Integer = posnStart To posnEnd
                strData = strData + strText(currentIndex)
            Next
            extractPMdataLength = Trim(strData)
        Else
            extractPMdataLength = ""
        End If
    End Function

    Function GetValveBitMask(ByVal profileNum As Integer) As String

        Select Case profileNum
            Case 0
                GetValveBitMask = My.Settings.asVP0.ToString
            Case 1
                GetValveBitMask = My.Settings.asVP1.ToString
            Case 2
                GetValveBitMask = My.Settings.asVP2.ToString
            Case 3
                GetValveBitMask = My.Settings.asVP3.ToString
            Case 4
                GetValveBitMask = My.Settings.asVP4.ToString
            Case 5
                GetValveBitMask = My.Settings.asVP5.ToString
            Case 6
                GetValveBitMask = My.Settings.asVP6.ToString
            Case 7
                GetValveBitMask = My.Settings.asVP7.ToString
        End Select
    End Function

    Private Function GetVPname(ByVal stepNum As Integer) As String
        Select Case stepNum
            Case -1
                GetVPname = "[none]"
            Case 0
                GetVPname = "FILLHLT"
            Case 1
                GetVPname = "FILLMASH"
            Case 2
                GetVPname = "ADDGRAIN"
            Case 3
                GetVPname = "MASHHEAT"
            Case 4
                GetVPname = "MASHIDLE"
            Case 5
                GetVPname = "SGARGEIN"
            Case 6
                GetVPname = "SPARGEOUT"
            Case 7
                GetVPname = "BOILADDN"
            Case 8
                GetVPname = "KETTLELID"
            Case 9
                GetVPname = "CHILLH2O"
            Case 10
                GetVPname = "CHILLBEER"
            Case 11
                GetVPname = "BOILRECIRC"
            Case 12
                GetVPname = "DRAIN"
            Case Else
                GetVPname = "[none]"
        End Select

    End Function

    Private Function CdegC(ByVal sngF) As Single

        CdegC = (sngF - 32) * 5 / 9

    End Function


#End Region

#Region "Recipe"

    Private Sub extractPMhopData(ByVal strText As String)

        Dim strStartText As String = "Hops" + vbCrLf + vbCrLf
        Dim strEndText As String = "Extras"
        Dim posnStart As Integer = 0
        Dim posnEnd As Integer = 0
        Dim newText As String = ""

        'clear any previously selected additions
        cbAddBoil.Checked = False
        cbAdd105.Checked = False
        cbAdd90.Checked = False
        cbAdd75.Checked = False
        cbAdd60.Checked = False
        cbAdd45.Checked = False
        cbAdd30.Checked = False
        cbAdd20.Checked = False
        cbAdd15.Checked = False
        cbAdd10.Checked = False
        cbAdd5.Checked = False
        cbAdd0.Checked = False

        'find string
        posnStart = InStr(strText, strStartText, CompareMethod.Text)
        If posnStart > 0 Then
            'we have found it
            posnStart = posnStart + strStartText.Length - 1   'new start position
            posnEnd = InStr(strText, strEndText, CompareMethod.Text)
            Dim charCut As Integer
            charCut = posnEnd - posnStart - 1
            'truncate string
            newText = strText.Substring(posnStart, charCut)
            'now we look for second occurrence of vbCrLf
            posnStart = InStr(newText, vbCrLf, CompareMethod.Text)
            If posnStart > 0 Then
                'found first end of line - truncate
                newText = newText.Substring(posnStart + 1)
            Else
                Exit Sub
            End If
            posnStart = InStr(newText, vbCrLf, CompareMethod.Text)
            If posnStart > 0 Then
                'found first end of line - truncate
                newText = newText.Substring(posnStart + 1)
            Else
                Exit Sub
            End If

            'now we have our starting point for hop data 
            'set up a loop to find all additions
            Dim blnEnd = False
            Dim Addn As String = ""
            While Not blnEnd
                'need to trim preceding table data (amount, type etc.)
                newText = newText.Substring(67)
                Addn = Trim(newText.Substring(0, 4))    'time part of hop addition
                Try
                    Select Case Val(Addn)
                        Case Is > 101
                            cbAdd105.Checked = True
                        Case 86 - 100
                            cbAdd90.Checked = True
                        Case 71 - 85
                            cbAdd75.Checked = True
                        Case 56 - 70
                            cbAdd60.Checked = True
                        Case 41 - 55
                            cbAdd45.Checked = True
                        Case 28 - 40
                            cbAdd30.Checked = True
                        Case 18 - 27
                            cbAdd20.Checked = True
                        Case 13 - 17
                            cbAdd15.Checked = True
                        Case 8 - 12
                            cbAdd10.Checked = True
                        Case 3 - 7
                            cbAdd5.Checked = True
                        Case 0 - 2
                            cbAdd0.Checked = True
                    End Select
                Catch ex As Exception

                End Try
                'look for end of line and trim
                posnStart = InStr(newText, vbCrLf, CompareMethod.Text)
                If posnStart > 0 Then
                    'found end of line - truncate to start of next
                    newText = newText.Substring(posnStart + 1)
                Else
                    Exit Sub
                End If
                If newText.Length < 72 Then
                    blnEnd = True
                End If
            End While
        End If

        'now do same for Extras
        strStartText = "Extras" + vbCrLf + vbCrLf
        strEndText = "Yeast"

        'find string
        posnStart = InStr(strText, strStartText, CompareMethod.Text)
        If posnStart > 0 Then
            'we have found it
            posnStart = posnStart + strStartText.Length - 1   'new start position
            posnEnd = InStr(strText, strEndText, CompareMethod.Text)
            Dim charCut As Integer
            charCut = posnEnd - posnStart - 1
            'truncate string
            newText = strText.Substring(posnStart, charCut)
            'now we look for second occurrence of vbCrLf
            posnStart = InStr(newText, vbCrLf, CompareMethod.Text)
            If posnStart > 0 Then
                'found first end of line - truncate
                newText = newText.Substring(posnStart + 1)
            Else
                Exit Sub
            End If
            posnStart = InStr(newText, vbCrLf, CompareMethod.Text)
            If posnStart > 0 Then
                'found first end of line - truncate
                newText = newText.Substring(posnStart + 1)
            Else
                Exit Sub
            End If

            'now we have our starting point for Extras data 
            'set up a loop to find all additions
            Dim blnEnd = False
            Dim Addn As String = ""
            While Not blnEnd
                'need to trim preceding table data (amount, type etc.)
                newText = newText.Substring(54)
                Addn = Trim(newText.Substring(0, 4))    'time part of hop addition
                Try
                    Select Case Val(Addn)
                        Case 105
                            cbAdd105.Checked = True
                        Case 60
                            cbAdd60.Checked = True
                        Case 45
                            cbAdd45.Checked = True
                        Case 30
                            cbAdd30.Checked = True
                        Case 15
                            cbAdd15.Checked = True
                        Case 10
                            cbAdd10.Checked = True
                        Case 5
                            cbAdd5.Checked = True
                        Case 0
                            cbAdd0.Checked = True
                    End Select
                Catch ex As Exception

                End Try
                'look for end of line and trim
                posnStart = InStr(newText, vbCrLf, CompareMethod.Text)
                If posnStart > 0 Then
                    'found end of line - truncate to start of next
                    newText = newText.Substring(posnStart + 1)
                Else
                    Exit Sub
                End If
                If newText.Length < 58 Then
                    blnEnd = True
                End If
            End While
        End If


    End Sub

    Private Sub DecodeProMash()

        Dim strDataFile As String = My.Settings.asStrRecipeFile

        'GET DATA FROM FILE
        '------------------

        Dim fs As FileStream = File.Open(strDataFile, FileMode.Open, FileAccess.Read)
        Dim sr As New StreamReader(fs)
        Dim strFile As String
        Dim strData As String
        Dim posn As Integer = 0
        Dim posnEnd As Integer = 0
        Try
            strFile = sr.ReadToEnd
            'extract data

            'determine if we are using litres or gallons
            Dim blnMetric As Boolean = False
            Dim strVolUnit As String = ""
            strVolUnit = extractPMdata(strFile, "Batch Size (", 0, ")")
            If strVolUnit = "L" Then
                blnMetric = True
            Else
                blnMetric = False
            End If
            'tbBrewDate.Text = extractPMdata(strFile, "Brewing Date:", 0, vbCr)
            tbRecipeName.Text = extractPMdata(strFile, "Recipe:", 0, vbCr)
            tbVol.Text = extractPMdataLength(strFile, "Batch Size", 8, 16)
            'tbStyle.Text = extractPMdata(strFile, "BJCP Style and Style Guidelines" + vbCr + vbLf + "-------------------------------" + vbCr + vbLf + vbCr + vbLf, 0, vbCr)
            'tbOG.Text = extractPMdata(strFile, "Anticipated OG:", 4, "Plato")
            tbDoughIn.Text = extractPMdata(strFile, "Dough In Temp:", 0, "Time:")
            tbSpargeLev.Text = extractPMdata(strFile, "Sparge Amount:", 0, "Sparge")
            If blnMetric Then
                tbMashLev.Text = extractPMdata(strFile, "Water L:", 0, "- Before")
            Else
                tbMashLev.Text = extractPMdata(strFile, "Water Gal:", 0, "- Before")
            End If
            tbBoilTotal.Text = extractPMdata(strFile, "Boil Time (min):", 0, "Evap")
            Call extractPMhopData(strFile)
            tbSpargeTemp.Text = extractPMdata(strFile, "Sparge Temp:", 0, "Time:")
            tbProteinTemp.Text = extractPMdata(strFile, "Protein Rest Temp:", 0, "Time:")
            If tbProteinTemp.Text.Length > 0 Then
                tbProteinTime.Text = extractPMdataBefore(strFile, "Saccharification Rest Temp:", 2, 3)
            Else
                tbProteinTime.Text = ""
            End If
            tbSacchTemp.Text = extractPMdata(strFile, "Saccharification Rest Temp:", 0, "Time:")
            tbSacchTime.Text = extractPMdataBefore(strFile, "Mash-out Rest Temp:", 2, 3)
            tbMOtemp.Text = extractPMdata(strFile, "Mash-out Rest Temp:", 0, "Time:")
            If tbMOtemp.Text.Length > 0 Then
                tbMOtime.Text = extractPMdataBefore(strFile, "Sparge Temp:", 2, 3)
            Else
                tbMOtime.Text = ""
            End If

        Catch ex As Exception

        End Try
        sr.Close()
        'Microsoft.VisualBasic.FileOpen(3, strDataFile, OpenMode.Input)

        'search for Recipe name:
        'Dim blnNotFound As Boolean = True
        'While blnNotFound

        '    Using My.Computer.FileSystem.OpenTextFileReader(strDataFile)

        '    End Using


        '    'Line Input #3, a$
        '    '            posn = InStr(a$, "Recipe:")   ' Get position.
        '    '            If posn <> 0 Then
        '    '                NotFound = False
        '    '                RecipeName = Trim(Mid$(a$, posn + 10, Len(a$) - 10))
        '    '                Debug.Print(RecipeName)
        '    '            Else
        '    '                'Debug.Print "searching..."
        '    '            End If

        'End While


    End Sub

    Private Sub GetBeerSmithList()

        'populates drop down combo box with available recipe names

        'clear existing items in combo box
        cboLoadedRecipe.Items.Clear()

        Dim bFound As Boolean = False
        Dim iStPosn, iEndPosn As Integer
        Dim strFind As String
        Dim strRecipeSubString As String

        strRecipeSubString = strXMLdata
        strFind = "<RECIPE>"
        While InStr(strRecipeSubString, strFind) <> 0
            'Find Recipe Name
            strFind = "<NAME>"
            iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind)
                bFound = True
                'and find end position
                strFind = "</NAME>"
                iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                cboLoadedRecipe.Items.Add(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
            End If
            strFind = "</RECIPE>"
            iStPosn = InStr(strRecipeSubString, strFind)  'Get end of current recipe data to truncate it
            strRecipeSubString = Mid$(strRecipeSubString, iStPosn + Len(strFind) + 1)
        End While
        cboLoadedRecipe.SelectedIndex = cboLoadedRecipe.Items.Count - 1



        'Dim xmldoc As New XmlDataDocument()
        'Dim xmlnode As XmlNodeList
        'Dim i As Integer
        'Dim str As String
        'Dim fs As New FileStream(My.Settings.asStrRecipeFile, FileMode.Open, FileAccess.Read)
        'xmldoc.Load(fs)
        'xmlnode = xmldoc.GetElementsByTagName("RECIPE")

        'For i = 0 To xmlnode.Count - 1
        '    xmlnode(i).ChildNodes.Item(0).InnerText.Trim()
        '    cboLoadedRecipe.Items.Add(xmlnode(i).ChildNodes.Item(0).InnerText.Trim())
        'Next

        'select first recipe
        cboLoadedRecipe.SelectedIndex = 0
        cboLoadedRecipe.Enabled = True

    End Sub
    Private Sub GetBTrecipeNames()
        'gets the names of each stored recipe on the BrewTroller and fills the session combo box

        'comm.Message = "GET_PROG 0"

        'tmrSendtoBT.Enabled = True
        For i = 0 To 29
            AddToTXstack("GET_PROG" + vbTab + Str(i) + vbCr)
            Sleep(400)
        Next

    End Sub

    Private Sub getAddns(ByVal intBits As Integer)

        'decodes integer into bits for boil additions and then displays data on session screen

        If intBits >= 2048 Then
            intBits = intBits - 2048
            cbAdd0.Checked = True
        Else
            cbAdd0.Checked = False
        End If

        If intBits >= 1024 Then
            intBits = intBits - 1024
            cbAdd5.Checked = True
        Else
            cbAdd5.Checked = False
        End If

        If intBits >= 512 Then
            intBits = intBits - 512
            cbAdd10.Checked = True
        Else
            cbAdd10.Checked = False
        End If

        If intBits >= 256 Then
            intBits = intBits - 256
            cbAdd15.Checked = True
        Else
            cbAdd15.Checked = False
        End If

        If intBits >= 128 Then
            intBits = intBits - 128
            cbAdd20.Checked = True
        Else
            cbAdd20.Checked = False
        End If

        If intBits >= 64 Then
            intBits = intBits - 64
            cbAdd30.Checked = True
        Else
            cbAdd30.Checked = False
        End If

        If intBits >= 32 Then
            intBits = intBits - 32
            cbAdd45.Checked = True
        Else
            cbAdd45.Checked = False
        End If

        If intBits >= 16 Then
            intBits = intBits - 16
            cbAdd60.Checked = True
        Else
            cbAdd60.Checked = False
        End If

        If intBits >= 8 Then
            intBits = intBits - 8
            cbAdd75.Checked = True
        Else
            cbAdd75.Checked = False
        End If

        If intBits >= 4 Then
            intBits = intBits - 4
            cbAdd90.Checked = True
        Else
            cbAdd90.Checked = False
        End If

        If intBits >= 2 Then
            intBits = intBits - 2
            cbAdd105.Checked = True
        Else
            cbAdd105.Checked = False
        End If

        If intBits >= 1 Then
            intBits = intBits - 1
            cbAddBoil.Checked = True
        Else
            cbAddBoil.Checked = False
        End If

    End Sub

    Private Sub ClearSessionVals()
        'clears session screen values
        cbAdd105.Checked = False
        txtAddn105.Text = ""
        cbAdd90.Checked = False
        txtAddn90.Text = ""
        cbAdd75.Checked = False
        txtAddn75.Text = ""
        cbAdd60.Checked = False
        txtAddn60.Text = ""
        cbAdd45.Checked = False
        txtAddn45.Text = ""
        cbAdd30.Checked = False
        txtAddn30.Text = ""
        cbAdd20.Checked = False
        txtAddn20.Text = ""
        cbAdd15.Checked = False
        txtAddn15.Text = ""
        cbAdd10.Checked = False
        txtAddn10.Text = ""
        cbAdd5.Checked = False
        txtAddn5.Text = ""
        cbAdd0.Checked = False
        txtAddn0.Text = ""
        txtMiscAddn.Text = ""
        tbProteinTemp.Text = ""
        tbProteinTime.Text = ""
        tbSacchTemp.Text = ""
        tbSacchTime.Text = ""
        tbMOtemp.Text = ""
        tbMOtime.Text = ""
        tbMashRatio.ForeColor = Color.Black
        tbDoughIn.ForeColor = Color.Black

    End Sub
    Private Sub GetRecipeXML()

        Dim bFound As Boolean = False
        Dim iStPosn, iEndPosn As Integer
        Dim strFind As String
        Dim strRecipeSubString, strRecipeFullString As String

        'Clear existing values
        Call ClearSessionVals()

        'Find the right recipe amongst all recipes

        strRecipeFullString = strXMLdata
        strFind = "</RECIPE>"
        Dim iRec As Integer

        For iRec = 0 To cboLoadedRecipe.SelectedIndex - 1
            If InStr(strRecipeFullString, strFind) <> 0 Then
                'Find End of Current Recipe file
                iStPosn = InStr(strRecipeFullString, strFind)  'Get end of current recipe data to truncate it
                strRecipeFullString = Mid$(strRecipeFullString, iStPosn + Len(strFind) + 1)
            End If
        Next

        'Find the Recipe we are after
        strFind = "<RECIPE>"
        iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
        If iStPosn <> 0 Then
            'Find end point of </RECIPE>
            strFind = "</RECIPE>"
            iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            'Cut redundant start of string for new search
            strRecipeFullString = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)

            'Find <RECIPE> data
            'Find <Name>
            strFind = "<NAME>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</NAME>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                Dim strRecipe As String = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
                Me.Text = "BrewTroller Remote: " & strRecipe
                tbRecipeName.Text = strRecipe
            End If

            'Find <Brewer>
            strFind = "<BREWER>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</BREWER>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                'strBrewer = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            End If

            'Find <ASST_BREWER>
            strFind = "<ASST_BREWER>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</ASST_BREWER>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                'strAsstBrewer = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            End If

            'Find <BATCH_SIZE>
            strFind = "<BATCH_SIZE>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</BATCH_SIZE>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                tbVol.Text = Format((CSng(Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)) * 1000), 0)
            End If

            'Find <BOIL_SIZE>
            strFind = "<BOIL_SIZE>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</BOIL_SIZE>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                'strBoilSize = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            End If

            'Find <BOIL_TIME>
            strFind = "<BOIL_TIME>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</BOIL_TIME>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                tbBoilTotal.Text = CInt(Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn))
            End If

            'Find <EFFICIENCY>
            strFind = "<EFFICIENCY>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</EFFICIENCY>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                'strEfficiency = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            End If

            'Find <GRAIN_TEMP>
            strFind = "<GRAIN_TEMP>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</GRAIN_TEMP>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                tbGrainTemp.Text = Format(CSng(Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)), "0")
            End If

            'find <TUN_TEMP>
            strFind = "<TUN_TEMP>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</TUN_TEMP>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                tbDoughIn.Text = Format(CSng(Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)), "0")
            Else
                tbDoughIn.Text = "??"
            End If

            'find <SPARGE_TEMP>
            strFind = "<SPARGE_TEMP>"
            iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            If iStPosn <> 0 Then
                iStPosn = iStPosn + Len(strFind) '- 1
                bFound = True
                'and find end position
                strFind = "</SPARGE_TEMP>"
                iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
                tbSpargeTemp.Text = Format(CSng(Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)), "0")
            Else
                'The ProMash sparge liquor temperature is derived from the Mash step titled 'Sparge'
            End If


        End If

        'Find hops
        strFind = "<HOPS>"
        iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
        If iStPosn <> 0 Then
            'truncate the string to only contain <HOPS> ... </HOPS>
            strFind = "</HOPS>"
            iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            strRecipeSubString = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            'strRecipeSubString contains <HOPS> ... </HOPS>

            Dim strHopName As String
            Dim strHopTime As Integer
            strFind = "<HOP>"
            Dim iCount As Integer = 0
            While InStr(strRecipeSubString, strFind) <> 0
                'Find iteration of <Hop>
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                'and now search for items within the hop information
                'find <NAME>
                strFind = "<NAME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</NAME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strHopName = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <ALPHA>
                strFind = "<ALPHA>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</ALPHA>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strHopName &= " " & Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn) & " (AA)"
                End If

                'find <AMOUNT>
                strFind = "<AMOUNT>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</AMOUNT>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strHopName &= " :" & Format(CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)) * 1000, " #0")
                End If

                'find <USE>
                strFind = "<USE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</USE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strHopUse(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <TIME>
                strFind = "<TIME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</TIME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strHopTime = CInt(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                End If
                'display information on session screen
                Call evalAddnInfo(strHopName, strHopTime)
                strFind = "</HOP>"
                iStPosn = InStr(strRecipeSubString, strFind)  'Get end of current hop data to truncate it
                strRecipeSubString = Mid$(strRecipeSubString, iStPosn + Len(strFind) + 1)
                iCount = iCount + 1
            End While
        End If

        'Find fermentables
        strFind = "<FERMENTABLES>"
        iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
        If iStPosn <> 0 Then
            'truncate the string to only contain <FERMENTABLES> ... </FERMENTABLES>
            strFind = "</FERMENTABLES>"
            iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            strRecipeSubString = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            'strRecipeSubString contains <FERMENTABLES> ... </FERMENTABLES>

            strFind = "<FERMENTABLE>"
            Dim sngGrainWeight As Single = 0
            Dim iCount As Integer = 0
            While InStr(strRecipeSubString, strFind) <> 0
                'Find iteration of <Hop>
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                'and now search for items within the hop information
                'find <NAME>
                strFind = "<NAME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</NAME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strFermName(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <TYPE>
                strFind = "<TYPE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</TYPE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strFermType(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <AMOUNT>
                strFind = "<AMOUNT>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</AMOUNT>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    sngGrainWeight += CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                End If

                'find <ADD_AFTER_BOIL>
                strFind = "<ADD_AFTER_BOIL>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</ADD_AFTER_BOIL>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strFermAddAfterBoil(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <COLOR>
                strFind = "<COLOR>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</COLOR>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strFermCol(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If
                strFind = "</FERMENTABLE>"
                'show total grain weight on session screen
                tbGrainWeight.Text = Format(CStr(sngGrainWeight) * 1000, "0")
                iStPosn = InStr(strRecipeSubString, strFind)  'Get end of current hop data to truncate it
                strRecipeSubString = Mid$(strRecipeSubString, iStPosn + Len(strFind) + 1)
                iCount = iCount + 1
            End While
        End If

        'Find  miscs
        strFind = "<MISCS>"
        iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
        If iStPosn <> 0 Then
            'truncate the string to only contain <MISCS> ... </MISCS>
            strFind = "</MISCS>"
            iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            strRecipeSubString = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            'strRecipeSubString contains <MISCS> ... </MISCS>

            Dim strMiscName As String
            Dim strMiscTime As String
            strFind = "<MISC>"
            Dim iCount As Integer = 0
            While InStr(strRecipeSubString, strFind) <> 0
                'Find iteration of <MISC>
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                'and now search for items within the hop information
                'find <NAME>
                strFind = "<NAME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</NAME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strMiscName = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <TYPE>
                strFind = "<TYPE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</TYPE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strMiscType(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <AMOUNT>
                strFind = "<AMOUNT>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</AMOUNT>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strMiscName &= " :" & Format(CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)), " #0.0 ")
                End If

                'find <USE>
                strFind = "<USE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</USE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strMiscUse(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <TIME>
                strFind = "<TIME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</TIME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strMiscTime = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If
                'display information on session screen
                If strMiscTime = "" Then
                    'this is a ProMash file and we don't have time information so place it in a generic box
                    If txtMiscAddn.Text = "" Then
                        txtMiscAddn.Text &= strMiscName
                    Else
                        txtMiscAddn.Text &= "; " & strMiscName
                    End If
                Else
                    'place details under the right additions step
                    Call evalAddnInfo(strMiscName, CInt(strMiscTime))
                End If

                strFind = "</MISC>"
                iStPosn = InStr(strRecipeSubString, strFind)  'Get end of current hop data to truncate it
                strRecipeSubString = Mid$(strRecipeSubString, iStPosn + Len(strFind) + 1)
                iCount = iCount + 1
            End While
        End If

        'Find  yeasts
        strFind = "<YEASTS>"
        iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
        If iStPosn <> 0 Then
            'truncate the string to only contain <YEASTS> ... </YEASTS>
            strFind = "</YEASTS>"
            iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            strRecipeSubString = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            'strRecipeSubString contains <YEASTS> ... </YEASTS>

            strFind = "<YEAST>"
            Dim sngMinTemp As Single
            Dim sngMaxTemp As Single
            Dim iCount As Integer = 0
            While InStr(strRecipeSubString, strFind) <> 0
                'Find iteration of <YEAST>
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                'and now search for items within the hop information
                'find <NAME>
                strFind = "<NAME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</NAME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strYeastName(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <TYPE>
                strFind = "<TYPE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</TYPE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strYeastType(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <FORM>
                strFind = "<FORM>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</FORM>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strYeastForm(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <MIN_TEMPERATURE>
                bFound = False
                strFind = "<MIN_TEMPERATURE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</MIN_TEMPERATURE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    sngMinTemp += CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                End If
                If Not bFound Then
                    strFind = "<MIN_TEMP>"
                    iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    If iStPosn <> 0 Then
                        iStPosn = iStPosn + Len(strFind)
                        bFound = True
                        'and find end position
                        strFind = "</MIN_TEMP>"
                        iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                        sngMinTemp += CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                    End If
                End If

                'find <MAX_TEMPERATURE>
                bFound = False
                strFind = "<MAX_TEMPERATURE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</MAX_TEMPERATURE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    sngMaxTemp += CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                End If
                If Not bFound Then
                    strFind = "<MAX_TEMP>"
                    iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    If iStPosn <> 0 Then
                        iStPosn = iStPosn + Len(strFind)
                        bFound = True
                        'and find end position
                        strFind = "</MAX_TEMP>"
                        iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                        sngMaxTemp += CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                    End If
                End If
                strFind = "</YEAST>"
                iStPosn = InStr(strRecipeSubString, strFind)  'Get end of current hop data to truncate it
                strRecipeSubString = Mid$(strRecipeSubString, iStPosn + Len(strFind) + 1)
                iCount = iCount + 1
            End While
            Dim sngAvTemp As Single
            sngAvTemp = (sngMinTemp + sngMaxTemp) / (iCount * 2)
            tbPitchTemp.Text = Format(sngAvTemp, "#0")
        End If

        'Find  MASH_STEPS
        strFind = "<MASH_STEPS>"
        iStPosn = InStr(strRecipeFullString, strFind)   ' Get position.
        If iStPosn <> 0 Then
            'truncate the string to only contain <MASH_STEPS> ... </MASH_STEPS>
            strFind = "</MASH_STEPS>"
            iEndPosn = InStr(strRecipeFullString, strFind)   ' Get position.
            strRecipeSubString = Mid$(strRecipeFullString, iStPosn, iEndPosn - iStPosn)
            'strRecipeSubString contains <MASH_STEPS> ... </MASH_STEPS>

            Dim sngMashTemp As Single
            Dim intMashTime As Integer
            Dim strMashName As String
            strFind = "<MASH_STEP>"
            Dim iCount As Integer = 0
            While InStr(strRecipeSubString, strFind) <> 0
                'Find iteration of <MASH_STEP>
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                'and now search for items within the hop information
                'find <NAME>
                strFind = "<NAME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</NAME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strMashName = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <TYPE>
                strFind = "<TYPE>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</TYPE>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strMashStepType(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <STEP_TIME>
                strFind = "<STEP_TIME>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</STEP_TIME>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    intMashTime = CInt(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                End If

                'find <STEP_TEMP>
                strFind = "<STEP_TEMP>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</STEP_TEMP>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    sngMashTemp = CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn))
                    If strMashName = "Sparge" Then
                        'this information is specific to the ProMash converter.
                        tbSpargeTemp.Text = Format(sngMashTemp, "#0")
                        'NOTE: BeerSmith derived XML locates this information under <MASH><SPARGE_TEMP>
                    End If
                End If

                'find <DESCRIPTION>
                strFind = "<DESCRIPTION>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</DESCRIPTION>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    'strMashStepDesc(iCount) = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                End If

                'find <WATER_GRAIN_RATIO>
                Dim strGrRatio As String
                strFind = "<WATER_GRAIN_RATIO>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</WATER_GRAIN_RATIO>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strGrRatio = Format(CSng(Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)) * 100, "##0")
                End If

                'find <INFUSE_TEMP>
                'first instance of infuse temp is used as the mash dough-in temperature
                Dim strInfuseTemp As String
                strFind = "<INFUSE_TEMP>"
                iStPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                If iStPosn <> 0 Then
                    iStPosn = iStPosn + Len(strFind)
                    bFound = True
                    'and find end position
                    strFind = "</INFUSE_TEMP>"
                    iEndPosn = InStr(strRecipeSubString, strFind)   ' Get position.
                    strInfuseTemp = Mid$(strRecipeSubString, iStPosn, iEndPosn - iStPosn)
                    strInfuseTemp = strInfuseTemp.Substring(0, strInfuseTemp.Length - 1).Trim
                    strInfuseTemp = Format(CSng(strInfuseTemp), "##0")
                End If


                'display mash step
                Select Case iCount
                    Case 0
                        tbProteinTemp.Text = sngMashTemp
                        tbProteinTime.Text = intMashTime
                        If strGrRatio = "" Then
                            'this information is not available
                            tbMashRatio.Text = "???"
                        Else
                            tbMashRatio.Text = strGrRatio
                        End If
                        If IsNumeric(strInfuseTemp) Then
                            tbDoughIn.Text = strInfuseTemp
                        Else
                            'parameter not available from xml files
                            tbDoughIn.Text = "??"
                        End If
                    Case 1
                        tbSacchTemp.Text = sngMashTemp
                        tbSacchTime.Text = intMashTime
                    Case 2
                        tbMOtemp.Text = sngMashTemp
                        tbMOtime.Text = intMashTime
                End Select

                strFind = "</MASH_STEP>"
                iStPosn = InStr(strRecipeSubString, strFind)  'Get end of current hop data to truncate it
                strRecipeSubString = Mid$(strRecipeSubString, iStPosn + Len(strFind) + 1)
                iCount = iCount + 1
            End While
            'tidy up final parameters
            tbDoughTime.Text = "?"    'this parameter not available from xml
        End If
    End Sub

    Private Sub evalAddnInfo(ByVal AddnDesc As String, ByVal AddnTime As Integer)

        Try
            If AddnTime > 101 Then
                cbAdd105.Checked = True
                txtAddn105.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn105, txtAddn105.Text)
            ElseIf AddnTime > 86 Then
                cbAdd90.Checked = True
                txtAddn90.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn90, txtAddn90.Text)
            ElseIf AddnTime > 71 Then
                cbAdd75.Checked = True
                txtAddn75.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn75, txtAddn75.Text)
            ElseIf AddnTime > 56 Then
                cbAdd60.Checked = True
                txtAddn60.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn60, txtAddn60.Text)
            ElseIf AddnTime > 41 Then
                cbAdd45.Checked = True
                txtAddn45.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn45, txtAddn45.Text)
            ElseIf AddnTime > 27 Then
                cbAdd30.Checked = True
                txtAddn30.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn30, txtAddn30.Text)
            ElseIf AddnTime > 17 Then
                cbAdd20.Checked = True
                txtAddn20.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn20, txtAddn20.Text)
            ElseIf AddnTime > 12 Then
                cbAdd15.Checked = True
                txtAddn15.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn15, txtAddn15.Text)
            ElseIf AddnTime > 7 Then
                cbAdd10.Checked = True
                txtAddn10.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn10, txtAddn10.Text)
            ElseIf AddnTime > 2 Then
                cbAdd5.Checked = True
                txtAddn5.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn5, txtAddn5.Text)
            Else
                cbAdd0.Checked = True
                txtAddn0.Text &= AddnDesc
                ToolTip1.SetToolTip(txtAddn0, txtAddn0.Text)
            End If

        Catch

        End Try

    End Sub

    Private Sub ClearAddns()
        'clears the current session tab boil addns to prepare for new values
        cbAddBoil.Checked = False
        cbAdd105.Checked = False
        cbAdd90.Checked = False
        cbAdd75.Checked = False
        cbAdd60.Checked = False
        cbAdd45.Checked = False
        cbAdd30.Checked = False
        cbAdd20.Checked = False
        cbAdd15.Checked = False
        cbAdd10.Checked = False
        cbAdd5.Checked = False
        cbAdd0.Checked = False
        txtAddnBoil.Text = ""
        txtAddn105.Text = ""
        txtAddn90.Text = ""
        txtAddn75.Text = ""
        txtAddn60.Text = ""
        txtAddn45.Text = ""
        txtAddn30.Text = ""
        txtAddn20.Text = ""
        txtAddn15.Text = ""
        txtAddn10.Text = ""
        txtAddn5.Text = ""
        txtAddn0.Text = ""
    End Sub


#End Region

#Region "Settings"

    Private Sub setInputLabels()

        'set input names from settings
        Dim IPlabel As String
        IPlabel = tblabelWItemp.Text
        Select Case cboDisplayWItemp.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Water In Temperature"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Water In Temperature"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Water In Temperature"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Water In Temperature"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Water In Temperature"
        End Select

        IPlabel = tblabelWOtemp.Text
        Select Case cboDisplayWOtemp.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Water Out Temperature"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Water Out Temperature"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Water Out Temperature"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Water Out Temperature"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Water Out Temperature"
        End Select

        IPlabel = tblabelAux1temp.Text
        Select Case cboDisplayAux1temp.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Aux 1 Temperature"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Aux 1 Temperature"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Aux 1 Temperature"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Aux 1 Temperature"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Aux 1 Temperature"
        End Select

        IPlabel = tblabelAux2temp.Text
        Select Case cboDisplayAux2temp.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Aux 2 Temperature"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Aux 2 Temperature"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Aux 2 Temperature"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Aux 2 Temperature"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Aux 2 Temperature"
        End Select

        IPlabel = tblabelBOtemp.Text
        Select Case cboDisplayBOtemp.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Beer Out Temperature"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Beer Out Temperature"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Beer Out Temperature"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Beer Out Temperature"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Beer Out Temperature"
        End Select

        IPlabel = tblabelHLTraw.Text
        Select Case cboDisplayHLTraw.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Raw HLT level"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Raw HLT level"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Raw HLT level"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Raw HLT level"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Raw HLT level"
        End Select

        IPlabel = tblabelKETraw.Text
        Select Case cboDisplayKETraw.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Raw Kettle level"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Raw Kettle level"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Raw Kettle level"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Raw Kettle level"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Raw Kettle level"
        End Select

        IPlabel = tblabelMTraw.Text
        Select Case cboDisplayMTraw.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Raw Mash Tun level"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Raw Mash Tun level"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Raw Mash Tun level"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Raw Mash Tun level"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Raw Mash Tun level"
        End Select

        IPlabel = tblabelSP.Text
        Select Case cboDisplaySP.Text
            Case "1"
                lbl1input.Text = IPlabel
                My.Settings.as1input = "Steam(Pressure)"
            Case "2"
                lbl2input.Text = IPlabel
                My.Settings.as2input = "Steam(Pressure)"
            Case "3"
                lbl3input.Text = IPlabel
                My.Settings.as3input = "Steam(Pressure)"
            Case "4"
                lbl4input.Text = IPlabel
                My.Settings.as4input = "Steam(Pressure)"
            Case "5"
                lbl5input.Text = IPlabel
                My.Settings.as5input = "Steam(Pressure)"
        End Select

        'lbl2input.Text = My.Settings.as2label
        'lbl3input.Text = My.Settings.as3label
        'lbl4input.Text = My.Settings.as4label
        'lbl5input.Text = My.Settings.as5label


    End Sub


#End Region

#Region "Redundant code"

    Private Sub oldx()



        Dim SigDocument As String = My.Settings.asStrRecipeFile
        Dim readerSettings As New XmlReaderSettings
        readerSettings.IgnoreWhitespace = True

        Try
            Using reader As XmlReader = _
                XmlReader.Create(SigDocument, readerSettings)
                While Not reader.EOF
                    ' Find the start of a recipe
                    If reader.IsStartElement("RECIPE") Then
                        'find recipe name that matches combo box list
                        reader.ReadToFollowing("NAME")
                        Dim strName As String = reader.ReadElementContentAsString()
                        If strName = cboLoadedRecipe.SelectedItem Then
                            'we have found our recipe
                            'write it to a new xml file
                            tbRecipeName.Text = strName
                            reader.ReadToFollowing("BATCH_SIZE")
                            tbVol.Text = reader.ReadElementContentAsString()
                            reader.ReadToFollowing("BOIL_TIME")
                            tbBoilTotal.Text = reader.ReadElementContentAsString()
                            'look for hops
                            'clear any previously selected additions
                            Call ClearAddns()

                            Dim hopTime As Single
                            Dim hopDesc As String
                            Dim strRead As String

                            reader.ReadToFollowing("HOPS")
                            reader.Read()
                            While reader.IsStartElement("HOP")
                                'strRead = reader.ReadString()
                                'strRead = "HOP"

                                reader.ReadToFollowing("NAME")
                                hopDesc = reader.ReadElementContentAsString()
                                reader.ReadToFollowing("ALPHA")
                                hopDesc &= ", " & reader.ReadElementContentAsString() & " (AA)"
                                reader.ReadToFollowing("TIME")
                                hopTime = reader.ReadElementContentAsFloat()
                                'send info to session tab
                                Try
                                    If hopTime > 101 Then
                                        cbAdd105.Checked = True
                                        txtAddn105.Text = hopDesc
                                    ElseIf hopTime > 86 Then
                                        cbAdd90.Checked = True
                                        txtAddn90.Text = hopDesc
                                    ElseIf hopTime > 71 Then
                                        cbAdd75.Checked = True
                                        txtAddn75.Text = hopDesc
                                    ElseIf hopTime > 56 Then
                                        cbAdd60.Checked = True
                                        txtAddn60.Text = hopDesc
                                    ElseIf hopTime > 41 Then
                                        cbAdd45.Checked = True
                                        txtAddn45.Text = hopDesc
                                    ElseIf hopTime > 27 Then
                                        cbAdd30.Checked = True
                                        txtAddn30.Text = hopDesc
                                    ElseIf hopTime > 17 Then
                                        cbAdd20.Checked = True
                                        txtAddn20.Text = hopDesc
                                    ElseIf hopTime > 12 Then
                                        cbAdd15.Checked = True
                                        txtAddn15.Text = hopDesc
                                    ElseIf hopTime > 7 Then
                                        cbAdd10.Checked = True
                                        txtAddn10.Text = hopDesc
                                    ElseIf hopTime > 2 Then
                                        cbAdd5.Checked = True
                                        txtAddn5.Text = hopDesc
                                    Else
                                        cbAdd0.Checked = True
                                        txtAddn0.Text = hopDesc
                                    End If

                                Catch

                                End Try
                                reader.ReadToFollowing("HOP")
                                'strRead = reader.Read()
                            End While

                        End If
                    Else
                        ' Read past nodes that are of no interest
                        reader.Read()
                    End If
                End While
            End Using
        Catch

        End Try

    End Sub



#End Region

#Region "Valves"


    Private Sub updateAutoValveStatus()
        Dim blnAutoValveOff As Boolean = True

        Select Case intCurrBTstep
            Case 1
                'check auto fill
                If My.Settings.asblnAutoFill Then
                    blnAutoValveOff = False
                    AddToTXstack(My.Settings.asCBauto_fill)
                End If
            Case 6 - 9
                'check auto mash
                If My.Settings.asblnAutoMash Then
                    blnAutoValveOff = False
                    AddToTXstack(My.Settings.asCBauto_mash)
                End If
            Case 11
                'check auto sparge
                If My.Settings.asblnAutoSparge Then
                    blnAutoValveOff = False
                    AddToTXstack(My.Settings.asCBauto_sparge)
                End If
            Case 13
                'check auto chill
                If My.Settings.asblnAutoChill Then
                    blnAutoValveOff = False
                    AddToTXstack(My.Settings.asCBauto_chill)
                End If
        End Select
        If blnAutoValveOff Then
            AddToTXstack(My.Settings.asCBauto_off)
        End If
    End Sub

    Private Sub UpdateValvePanel(ByVal VlvBitMask As Single)

        Dim vlvnum As Integer = 32

        For vlvnum = 1 To 32
            If ExamineBit(VlvBitMask, vlvnum) Then
                DoVlvSetting(vlvnum, True)
            Else
                DoVlvSetting(vlvnum, False)
            End If

            'vlvnum -= 1
        Next

    End Sub

    Private Sub DoVlvSetting(ByVal SettingNumber As Integer, ByVal SettingValue As Boolean)
        'Exit Sub
        Select Case SettingNumber
            Case 1
                If Settings.v1 <> SettingValue Then Settings.v1 = SettingValue
            Case 2
                If Settings.v2 <> SettingValue Then Settings.v2 = SettingValue
            Case 3
                If Settings.v3 <> SettingValue Then Settings.v3 = SettingValue
            Case 4
                If Settings.v4 <> SettingValue Then Settings.v4 = SettingValue
            Case 5
                If Settings.v5 <> SettingValue Then Settings.v5 = SettingValue
            Case 6
                If Settings.v6 <> SettingValue Then Settings.v6 = SettingValue
            Case 7
                If Settings.v7 <> SettingValue Then Settings.v7 = SettingValue
            Case 8
                If Settings.v8 <> SettingValue Then Settings.v8 = SettingValue
            Case 9
                If Settings.v9 <> SettingValue Then Settings.v9 = SettingValue
            Case 10
                If Settings.v10 <> SettingValue Then Settings.v10 = SettingValue
            Case 11
                If Settings.v11 <> SettingValue Then Settings.v11 = SettingValue
            Case 12
                If Settings.v12 <> SettingValue Then Settings.v12 = SettingValue
            Case 13
                If Settings.v13 <> SettingValue Then Settings.v13 = SettingValue
            Case 14
                If Settings.v14 <> SettingValue Then Settings.v14 = SettingValue
            Case 15
                If Settings.v15 <> SettingValue Then Settings.v15 = SettingValue
            Case 16
                If Settings.v16 <> SettingValue Then Settings.v16 = SettingValue

        End Select

    End Sub

#End Region

    Private Sub rtbBTtx_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rtbBTtx.TextChanged
        'if we are updating the comms tab then copy contents there
        If blnUpdateCommsTAB Then
            rtbBTtxComms.Lines = rtbBTtx.Lines
        End If
    End Sub

    Private Sub rbBT1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles rbBT1.CheckedChanged, rbBT2.CheckedChanged, rbFT.CheckedChanged
        If rbBT1.Checked Then
            Settings.asBTversion = "BT1"
            Me.Text = "BTremote for BrewTroller 1.x"
            Me.tb2Unit.Visible = False
            Me.tbGrainTemp.Visible = True
            Me.lblRecipeUnits.Visible = False
            Me.lblGrainTemp.Visible = True
            Me.lbl2Acid.Enabled = False
            Me.tb2AcidTemp.Enabled = False
            Me.tb2AcidTime.Enabled = False
            Me.lbl2Sacch2.Enabled = False
            Me.tb2Sacch2Temp.Enabled = False
            Me.tb2Sacch2Time.Enabled = False
            Me.cbAskSlotOverWrite.Visible = True
            Me.lblTimer2.Enabled = False
            Me.btnTim2Dwn.Enabled = False
            Me.btnTim2RunPause.Enabled = False
            Me.btnTim2Up.Enabled = False
            Me.btnTimer2Stop.Enabled = False
            Me.CommandToolStripMenuItem.Visible = True
            Me.ControlToolStripMenuItem.Visible = False
            'set up recipe names combo box (session tab)
            cboBTrecipeSlot.Items.Clear()
            cboBTrecipeSlot.Items.Add("**Autobrew**")
            For i = 0 To 29
                cboBTrecipeSlot.Items.Add("Slot " + Str(i))
                strBTrecipeNames(i) = "Slot " + Str(i)
            Next
            cboBTrecipeSlot.Text = "Slot 0"
        ElseIf rbBT2.Checked Then
            Settings.asBTversion = "BT2"
            Me.Text = "BTremote for BrewTroller 2.x"
            Me.tb2Unit.Visible = True
            Me.tbGrainTemp.Visible = False
            Me.lblRecipeUnits.Visible = True
            Me.lblGrainTemp.Visible = False
            Me.lbl2Acid.Enabled = True
            Me.tb2AcidTemp.Enabled = True
            Me.tb2AcidTime.Enabled = True
            Me.lbl2Sacch2.Enabled = True
            Me.tb2Sacch2Temp.Enabled = True
            Me.tb2Sacch2Time.Enabled = True
            Me.cbAskSlotOverWrite.Visible = False
            Me.lblTimer2.Enabled = True
            Me.btnTim2Dwn.Enabled = True
            Me.btnTim2RunPause.Enabled = True
            Me.btnTim2Up.Enabled = True
            Me.btnTimer2Stop.Enabled = True
            Me.CommandToolStripMenuItem.Visible = False
            Me.ControlToolStripMenuItem.Visible = True
            'set up recipe names combo box (session tab)
            cboBTrecipeSlot.Items.Clear()
            For i = 0 To 19
                cboBTrecipeSlot.Items.Add("Slot " + Str(i))
                strBTrecipeNames(i) = "Slot " + Str(i)
            Next
            cboBTrecipeSlot.Text = "Slot 0"
        Else
            Settings.asBTversion = "FT"
            Me.Text = "BTremote for FermTroller"
        End If
    End Sub

    Private Sub tb2AcidTemp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb2AcidTemp.TextChanged
        Dim tb As New TextBox
        tb = tb2AcidTemp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tb2AcidTime_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb2AcidTime.TextChanged
        Dim tb As New TextBox
        tb = tb2AcidTime
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next
    End Sub

    Private Sub tb2Sacch2Temp_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb2Sacch2Temp.TextChanged
        Dim tb As New TextBox
        tb = tb2Sacch2Temp
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub tb2Sacch2Time_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb2Sacch2Time.TextChanged
        Dim tb As New TextBox
        tb = tb2Sacch2Time
        For i = 0 To tb.Text.Length - 1
            If IsNumeric(tb.Text.Substring(i, 1)) Then
                tb.ForeColor = Color.Black
            Else
                tb.ForeColor = Color.Red
                Exit Sub
            End If
        Next

    End Sub

    Private Sub cbReset_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbReset.CheckedChanged
        If cbReset.Checked = True Then
            If DisplayInfo(DI_BUILD) = "unknown" Then
                DisplayInfo(DI_VER) = ""
                DisplayInfo(DI_BUILD) = ""
            End If
        End If
    End Sub

    Private Sub ChangeValueToolStripMenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ChangeValueToolStripMenuItem3.Click

        Dim strVal As String = InputBox("Enter timer value :", , "mm:ss")

        'change entered separator to ':'
        strVal = strVal.Replace(".", ":")
        strVal = strVal.Replace(" ", ":")

        Dim hhmm As String() = Nothing
        Dim hrVal As String = Nothing
        Dim minVal As String = Nothing
        Dim secVal As String = Nothing
        Dim millis As Double = 0

        hhmm = strVal.Split(":")

        Dim s As String
        Dim item As Integer = 0

        For Each s In hhmm
            If Not IsNumeric(s) Then
                MsgBox("Please enter a valid time in format " + vbCrLf + "'mm:ss' or 'hh:mm:ss' OR " + vbCrLf + "'mm.ss' or 'hh.mm.ss' OR" + vbCrLf + "'mm ss' or 'hh mm ss'", MsgBoxStyle.Exclamation)
                Exit Sub
            End If
            If item = 0 Then
                hrVal = s
            ElseIf item = 1 Then
                minVal = s
            ElseIf item = 2 Then
                secVal = s
            End If

            item += 1

        Next s

        If secVal = Nothing Then
            'we only had two items, shift them to represent mins and secs rather than hrs and mins
            secVal = minVal
            minVal = hrVal
            hrVal = Nothing
        End If
        'work out millis
        millis = CInt(hrVal) * 3600000 + CInt(minVal) * 60000 + CInt(secVal) * 1000

        AddToTXstack("SET_TIMERVALUE+1+" + CStr(millis) + "-")

    End Sub

    Private Sub ChangeValueToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ChangeValueToolStripMenuItem2.Click
        Dim strVal As String = InputBox("Enter timer value :", , "mm:ss")

        'change entered separator to ':'
        strVal = strVal.Replace(".", ":")
        strVal = strVal.Replace(" ", ":")

        Dim hhmm As String() = Nothing
        Dim hrVal As String = Nothing
        Dim minVal As String = Nothing
        Dim secVal As String = Nothing
        Dim millis As Double = 0

        hhmm = strVal.Split(":")

        Dim s As String
        Dim item As Integer = 0

        For Each s In hhmm
            If Not IsNumeric(s) Then
                MsgBox("Please enter a valid time in format " + vbCrLf + "'mm:ss' or 'hh:mm:ss' OR " + vbCrLf + "'mm.ss' or 'hh.mm.ss' OR" + vbCrLf + "'mm ss' or 'hh mm ss'", MsgBoxStyle.Exclamation)
                Exit Sub
            End If
            If item = 0 Then
                hrVal = s
            ElseIf item = 1 Then
                minVal = s
            ElseIf item = 2 Then
                secVal = s
            End If

            item += 1

        Next s

        If secVal = Nothing Then
            'we only had two items, shift them to represent mins and secs rather than hrs and mins
            secVal = minVal
            minVal = hrVal
            hrVal = Nothing
        End If
        'work out millis
        millis = CInt(hrVal) * 3600000 + CInt(minVal) * 60000 + CInt(secVal) * 1000

        AddToTXstack("SET_TIMERVALUE+0+" + CStr(millis) + "-")

    End Sub

    Private Sub StartToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartToolStripMenuItem.Click
        If DlgBoxProgStart.ShowDialog = Windows.Forms.DialogResult.OK Then
            Dim strRecipeNum As String
            Dim strProgramStep As String
            strRecipeNum = DlgBoxProgStart.cboRecipe.SelectedIndex.ToString
            strProgramStep = DlgBoxProgStart.cboStep.SelectedIndex.ToString
            AddToTXstack("INIT_STEP+" + strRecipeNum + "+" + strProgramStep)
            If DlgBoxProgStart.CheckBox1.Checked Then
                'send init_step for second program
                strRecipeNum = DlgBoxProgStart.cboRecipeB.SelectedIndex.ToString
                strProgramStep = DlgBoxProgStart.cboStepB.SelectedIndex.ToString
                AddToTXstack("INIT_STEP+" + strRecipeNum + "+" + strProgramStep)
            End If
        End If

    End Sub

    Private Sub StepToToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StepToToolStripMenuItem1.Click
        If DlgBoxProgStart.ShowDialog = Windows.Forms.DialogResult.OK Then
            Dim strRecipeNum As String
            Dim strProgramStep As String
            strRecipeNum = DlgBoxProgStart.cboRecipe.SelectedIndex.ToString
            strProgramStep = DlgBoxProgStart.cboStep.SelectedIndex.ToString
            AddToTXstack("ADV_STEP+" + "+" + strProgramStep)
        End If

    End Sub

    Private Sub SetHLTToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SetHLTToolStripMenuItem1.Click

        Dim strSet As String

        strSet = InputBox("Enter setpoint:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_SETPOINT+0+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If

    End Sub

    Private Sub SetMashToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SetMashToolStripMenuItem1.Click
        Dim strSet As String

        strSet = InputBox("Enter setpoint:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_SETPOINT+1+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If

    End Sub

    Private Sub SetKettleToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SetKettleToolStripMenuItem1.Click
        Dim strSet As String

        strSet = InputBox("Enter setpoint:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_SETPOINT+2+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If

    End Sub

    Private Sub ClearHLTToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearHLTToolStripMenuItem1.Click
        AddToTXstack("SET_SETPOINT+0+0-")

    End Sub

    Private Sub ClearMashToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearMashToolStripMenuItem1.Click
        AddToTXstack("SET_SETPOINT+1+0-")

    End Sub

    Private Sub ClearKettleToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearKettleToolStripMenuItem1.Click
        AddToTXstack("SET_SETPOINT+2+0-")

    End Sub

    Private Sub AutoFillToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoFillToolStripMenuItem.Click
        If Me.AutoFillToolStripMenuItem.Checked = True Then
            Me.AutoFillToolStripMenuItem.Checked = False
        Else
            Me.AutoFillToolStripMenuItem.Checked = True
        End If
        setAutoValve()
    End Sub

    Private Sub AutoMashToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoMashToolStripMenuItem.Click
        If Me.AutoMashToolStripMenuItem.Checked = True Then
            Me.AutoMashToolStripMenuItem.Checked = False
        Else
            Me.AutoMashToolStripMenuItem.Checked = True
        End If
        setAutoValve()
    End Sub

    Private Sub AutoSpargeToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoSpargeToolStripMenuItem.Click
        If Me.AutoSpargeToolStripMenuItem.Checked = True Then
            Me.AutoSpargeToolStripMenuItem.Checked = False
        Else
            Me.AutoSpargeToolStripMenuItem.Checked = True
        End If
        setAutoValve()
    End Sub

    Private Sub AutoChillToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutoChillToolStripMenuItem.Click
        If Me.AutoChillToolStripMenuItem.Checked = True Then
            Me.AutoChillToolStripMenuItem.Checked = False
        Else
            Me.AutoChillToolStripMenuItem.Checked = True
        End If
        setAutoValve()
    End Sub

    Private Sub setAutoValve()
        Dim intAutoVlv As Integer = 0
        If Me.AutoFillToolStripMenuItem.Checked Then intAutoVlv += 1
        If Me.AutoMashToolStripMenuItem.Checked Then intAutoVlv += 2
        If Me.AutoSpargeToolStripMenuItem.Checked Then intAutoVlv += 4
        If Me.AutoChillToolStripMenuItem.Checked Then intAutoVlv += 8
        AddToTXstack("SET_AUTOVLV+" & intAutoVlv.ToString & "-")
    End Sub

    Private Sub ClearAllToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearAllToolStripMenuItem.Click
        Me.AutoFillToolStripMenuItem.Checked = False
        Me.AutoMashToolStripMenuItem.Checked = False
        Me.AutoSpargeToolStripMenuItem.Checked = False
        Me.AutoChillToolStripMenuItem.Checked = False
        setAutoValve()
    End Sub

    Private Sub GetBoilSettingToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetBoilSettingToolStripMenuItem.Click
        AddToTXstack("GET_BOIL-")
        blnShowBoil = True
    End Sub

    Private Sub VesselToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles VesselToolStripMenuItem.Click
        If CInt(DisplayInfo(DI_HLT_CAPACITY)) = 0 Or CInt(DisplayInfo(DI_MASH_CAPACITY)) = 0 Or CInt(DisplayInfo(DI_KET_CAPACITY)) = 0 Then
            tsslMiscInfo.Text = "please wait ... retrieving settings"
            tsslMiscInfo.Visible = True
            tmrMessages.Interval = 10000  '10 seconds
            tmrMessages.Enabled = True    'show message for one timer tick
            AddToTXstack("GET_VSET+0-")
            AddToTXstack("GET_VSET+1-")
            AddToTXstack("GET_VSET+2-")
            blnShowVsetDialog = True
        Else
            If DlgBoxVset.ShowDialog = Windows.Forms.DialogResult.OK Then
                Dim strCapacity As String
                Dim strDeadSpace As String
                strCapacity = DlgBoxVset.tbHLTcap.Text
                strDeadSpace = DlgBoxVset.tbHLTds.Text
                AddToTXstack("SET_VSET+0+" + strCapacity + "+" + strDeadSpace + "-")
                strCapacity = DlgBoxVset.tbMASHcap.Text
                strDeadSpace = DlgBoxVset.tbMASHds.Text
                AddToTXstack("SET_VSET+1+" + strCapacity + "+" + strDeadSpace + "-")
                strCapacity = DlgBoxVset.tbKETcap.Text
                strDeadSpace = DlgBoxVset.tbKETds.Text
                AddToTXstack("SET_VSET+2+" + strCapacity + "+" + strDeadSpace + "-")
            End If
        End If

    End Sub

    Private Sub ProgramToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Me.tcMain.SelectedIndex = 3

    End Sub

    Private Sub ValvesToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ValvesToolStripMenuItem.Click
        If dlgValveProfile.ShowDialog = Windows.Forms.DialogResult.OK Then

        End If

    End Sub

    Private Sub TempSensorsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TempSensorsToolStripMenuItem.Click
        If DlgTempSensors.ShowDialog = Windows.Forms.DialogResult.OK Then

        End If

    End Sub

    Private Sub CheckBox2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

    Private Sub cbV32_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV32.CheckedChanged

    End Sub

    Private Sub cbV30_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV30.CheckedChanged

    End Sub

    Private Sub cbV29_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV29.CheckedChanged

    End Sub

    Private Sub cbV1_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbV1.GotFocus
        SetActive(sender)
    End Sub

    Private Sub cbV16_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV16.CheckedChanged

    End Sub

    Private Sub cbV14_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV14.CheckedChanged

    End Sub

    Private Sub cbV13_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV13.CheckedChanged

    End Sub

    Private Sub cbV12_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbV12.CheckedChanged

    End Sub

    Private Sub cbV2_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbV2.GotFocus, cbV3.GotFocus, cbV4.GotFocus, cbV5.GotFocus, _
                cbV6.GotFocus, cbV7.GotFocus, cbV8.GotFocus, cbV9.GotFocus, cbV10.GotFocus, cbV11.GotFocus, cbV12.GotFocus, _
                cbV13.GotFocus, cbV14.GotFocus, cbV15.GotFocus, cbV16.GotFocus
        SetActive(sender)
    End Sub

    Private Sub lblT0_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblT0.Click, lblT1.Click, _
                lblT2.Click, lblT3.Click, lblT4.Click, lblT5.Click, lblT6.Click, lblT7.Click, lblT8.Click
        SetActive(sender)
    End Sub

    Private Sub lblT0_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles lblT0.GotFocus

    End Sub

    Private Sub cbLogData_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbLogData.CheckedChanged
        If cbLogData.Checked = False Then
            tsslLogMsg.Text = "No log"
        Else
            tsslLogMsg.Text = "Log on"
        End If
    End Sub

    Private Sub SoftRebootToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SoftRebootToolStripMenuItem1.Click
        AddToTXstack("RESET+1-")
    End Sub

    Private Sub RESETALLToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RESETALLToolStripMenuItem1.Click
        AddToTXstack("RESET+0-")
    End Sub

    Private Sub OnToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OnToolStripMenuItem2.Click
        AddToTXstack("SET_ALARM+1-")
    End Sub

    Private Sub OffToolStripMenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OffToolStripMenuItem3.Click
        AddToTXstack("SET_ALARM+0-")
    End Sub

    Private Sub OnToolStripMenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        AddToTXstack("SET_LOGSTATUS+1-")
    End Sub

    Private Sub OffToolStripMenuItem4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        AddToTXstack("SET_LOGSTATUS+0-")
    End Sub

    Private Sub RunToolStripMenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RunToolStripMenuItem3.Click
        AddToTXstack("SET_TIMERSTATUS+0+1-")
    End Sub

    Private Sub PauseToolStripMenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PauseToolStripMenuItem3.Click
        AddToTXstack("SET_TIMERSTATUS+0+0-")
    End Sub

    Private Sub ClearToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearToolStripMenuItem.Click
        AddToTXstack("SET_TIMERVALUE+0+0-")
    End Sub

    Private Sub ClearToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearToolStripMenuItem1.Click
        AddToTXstack("SET_TIMERVALUE+1+0-")
    End Sub

    Private Sub RunToolStripMenuItem4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RunToolStripMenuItem4.Click
        AddToTXstack("SET_TIMERSTATUS+1+1-")
    End Sub

    Private Sub PauseToolStripMenuItem4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PauseToolStripMenuItem4.Click
        AddToTXstack("SET_TIMERSTATUS+1+0-")
    End Sub

    Private Sub SetBoilTriggerToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SetBoilTriggerToolStripMenuItem.Click
        Dim strSet As String

        strSet = InputBox("Enter boil trigger point:", "")
        If IsNumeric(strSet) Then
            strSet = CStr(CInt(strSet))  'ensure it is in integer format
            AddToTXstack("SET_BOIL+" + strSet + "-")
        Else
            MsgBox("Setpoint value was not a valid number", MsgBoxStyle.Exclamation)
        End If

    End Sub

    Private Sub HeaterOutputsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HeaterOutputsToolStripMenuItem.Click
        dlgOutputSet.ShowDialog()
    End Sub

End Class
